Skip to content

Commit

Permalink
infer sigv4 region from environment (#412)
Browse files Browse the repository at this point in the history
* infer sigv4 region from environment

* document test

* aws.StringValue
  • Loading branch information
rfratto authored Feb 18, 2021
1 parent bbf8e1d commit c18cde2
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ update your local checkouts of the repository to point at the new branch name.
- [ENHANCEMENT] Allow specifying custom wal_truncate_frequency per integration.
(@rfratto)

- [ENHANCEMENT] The SigV4 region can now be inferred using the shared config
(at `$HOME/.aws/config`) or environment variables (via `AWS_CONFIG`).
(@rfratto)

- [BUGFIX] Not providing an `-addr` flag for `agentctl config-sync` will no
longer report an error and will instead use the pre-existing default value.
(@rfratto)
Expand Down
16 changes: 9 additions & 7 deletions docs/configuration-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1818,19 +1818,21 @@ basic_auth:
#
# https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials
#
# When enabled, region must be supplied.
# Region must be supplied if it cannot be inferred from the shared config
# ($HOME/.aws/config when AWS_SDK_LOAD_CONFIG is truthy) or the environment
# (AWS_REGION).
#
# This feature is currently exclusive to the Grafana Cloud Agent and is only
# currently available for remote_write of Prometheus metrics.
# This feature is only currently available for remote_write of Prometheus
# metrics.
sigv4:
# Enable SigV4 request signing. May not be enabled at the same time as
# configuring basic auth or bearer_token/bearer_token_file.
[ enabled: <boolean> | default = false ]

# Region to use for signing the requests. When sigv4.enabled is true,
# must be non-empty and must be the region of the AMP workspace specified
# by the remote_write URL.
region: <string>
# Region to use for signing the requests. Must be supplied if region cannot
# be inferred from environment. Region must match the region of the AMP
# workspace specified by the remote_write URL.
[region: <string>]

# Configures the remote write request's TLS settings.
tls_config:
Expand Down
17 changes: 8 additions & 9 deletions pkg/prom/instance/sigv4.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ type SigV4Config struct {
}

type sigV4RoundTripper struct {
cfg SigV4Config
next http.RoundTripper
pool sync.Pool
region string
next http.RoundTripper
pool sync.Pool

signer *signer.Signer
}
Expand All @@ -36,10 +36,6 @@ type sigV4RoundTripper struct {
// Credentials for signing are retrieving used the default AWS credential chain.
// If credentials could not be found, an error will be returned.
func NewSigV4RoundTripper(cfg SigV4Config, next http.RoundTripper) (http.RoundTripper, error) {
if cfg.Region == "" {
return nil, fmt.Errorf("region not configured")
}

if next == nil {
next = http.DefaultTransport
}
Expand All @@ -53,9 +49,12 @@ func NewSigV4RoundTripper(cfg SigV4Config, next http.RoundTripper) (http.RoundTr
if _, err := sess.Config.Credentials.Get(); err != nil {
return nil, fmt.Errorf("could not get sigv4 credentials: %w", err)
}
if aws.StringValue(sess.Config.Region) == "" {
return nil, fmt.Errorf("region not configured in sigv4 or in default credentials chain")
}

rt := &sigV4RoundTripper{
cfg: cfg,
region: cfg.Region,
next: next,
signer: signer.NewSigner(sess.Config.Credentials),
}
Expand Down Expand Up @@ -88,7 +87,7 @@ func (rt *sigV4RoundTripper) RoundTrip(req *http.Request) (*http.Response, error
}()
req.Body = ioutil.NopCloser(seeker)

_, err := rt.signer.Sign(req, seeker, "aps", rt.cfg.Region, time.Now().UTC())
_, err := rt.signer.Sign(req, seeker, "aps", rt.region, time.Now().UTC())
if err != nil {
return nil, fmt.Errorf("failed to sign request: %w", err)
}
Expand Down
26 changes: 22 additions & 4 deletions pkg/prom/instance/sigv4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,41 @@ package instance

import (
"net/http"
"os"
"strings"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
signer "github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/stretchr/testify/require"
)

func TestSigV4_Inferred_Region(t *testing.T) {
os.Setenv("AWS_ACCESS_KEY_ID", "secret")
os.Setenv("AWS_SECRET_ACCESS_KEY", "token")
os.Setenv("AWS_REGION", "us-west-2")

sess, err := session.NewSession(&aws.Config{
// Setting to an empty string to demostrate the default value from the yaml
// won't override the environment's region.
Region: aws.String(""),
})
require.NoError(t, err)
_, err = sess.Config.Credentials.Get()
require.NoError(t, err)

require.NotNil(t, sess.Config.Region)
require.Equal(t, "us-west-2", *sess.Config.Region)
}

func TestSigV4RoundTripper(t *testing.T) {
var gotReq *http.Request

rt := &sigV4RoundTripper{
cfg: SigV4Config{
Enabled: true,
Region: "us-east-2",
},
region: "us-east-2",
next: promhttp.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
gotReq = req
return &http.Response{StatusCode: http.StatusOK}, nil
Expand Down

0 comments on commit c18cde2

Please sign in to comment.