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

infer sigv4 region from environment #412

Merged
merged 3 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
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 sess.Config.Region == nil || *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