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

feat: support sigv4 signing #169

Merged
merged 14 commits into from
Oct 28, 2024
9 changes: 9 additions & 0 deletions pkg/remote/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"crypto/tls"
"fmt"
"github.com/grafana/xk6-output-prometheus-remote/pkg/sigv4"
"io"
"math"
"net/http"
Expand All @@ -22,6 +23,7 @@ type HTTPConfig struct {
Timeout time.Duration
TLSConfig *tls.Config
BasicAuth *BasicAuth
SigV4 *sigv4.Config
Headers http.Header
}

Expand Down Expand Up @@ -60,6 +62,13 @@ func NewWriteClient(endpoint string, cfg *HTTPConfig) (*WriteClient, error) {
TLSClientConfig: cfg.TLSConfig,
}
}
if cfg.SigV4 != nil {
tripper, err := sigv4.NewRoundTripper(cfg.SigV4, wc.hc.Transport)
if err != nil {
return nil, err
}
wc.hc.Transport = tripper
}
return wc, nil
}

Expand Down
45 changes: 45 additions & 0 deletions pkg/remotewrite/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"github.com/grafana/xk6-output-prometheus-remote/pkg/sigv4"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -68,6 +69,15 @@ type Config struct {
TrendStats []string `json:"trendStats"`

StaleMarkers null.Bool `json:"staleMarkers"`

// SigV4Region is the AWS region where the workspace is.
SigV4Region null.String `json:"sigV4Region"`

// SigV4AccessKey is the AWS access key.
SigV4AccessKey null.String `json:"sigV4AccessKey"`

// SigV4SecretKey is the AWS secret key.
SigV4SecretKey null.String `json:"sigV4SecretKey"`
}

// NewConfig creates an Output's configuration.
Expand All @@ -81,6 +91,9 @@ func NewConfig() Config {
Headers: make(map[string]string),
TrendStats: defaultTrendStats,
StaleMarkers: null.BoolFrom(false),
SigV4Region: null.NewString("", false),
SigV4AccessKey: null.NewString("", false),
SigV4SecretKey: null.NewString("", false),
}
}

Expand Down Expand Up @@ -110,6 +123,14 @@ func (conf Config) RemoteConfig() (*remote.HTTPConfig, error) {
hc.TLSConfig.Certificates = []tls.Certificate{cert}
}

if conf.SigV4Region.Valid && conf.SigV4AccessKey.Valid && conf.SigV4SecretKey.Valid {
hc.SigV4 = &sigv4.Config{
Region: conf.SigV4Region.String,
AwsAccessKeyID: conf.SigV4AccessKey.String,
AwsSecretAccessKey: conf.SigV4SecretKey.String,
}
}

if len(conf.Headers) > 0 {
hc.Headers = make(http.Header)
for k, v := range conf.Headers {
Expand Down Expand Up @@ -149,6 +170,18 @@ func (conf Config) Apply(applied Config) Config {
conf.BearerToken = applied.BearerToken
}

if applied.SigV4Region.Valid {
conf.SigV4Region = applied.SigV4Region
}

if applied.SigV4AccessKey.Valid {
conf.SigV4AccessKey = applied.SigV4AccessKey
}

if applied.SigV4SecretKey.Valid {
conf.SigV4SecretKey = applied.SigV4SecretKey
}

if applied.PushInterval.Valid {
conf.PushInterval = applied.PushInterval
}
Expand Down Expand Up @@ -299,6 +332,18 @@ func parseEnvs(env map[string]string) (Config, error) {
}
}

if sigV4Region, sigV4RegionDefined := env["K6_PROMETHEUS_RW_SIGV4_REGION"]; sigV4RegionDefined {
c.SigV4Region = null.StringFrom(sigV4Region)
}

if sigV4AccessKey, sigV4AccessKeyDefined := env["K6_PROMETHEUS_RW_SIGV4_ACCESS_KEY"]; sigV4AccessKeyDefined {
c.SigV4AccessKey = null.StringFrom(sigV4AccessKey)
}

if sigV4SecretKey, sigV4SecretKeyDefined := env["K6_PROMETHEUS_RW_SIGV4_SECRET_KEY"]; sigV4SecretKeyDefined {
c.SigV4SecretKey = null.StringFrom(sigV4SecretKey)
}

if b, err := envBool(env, "K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM"); err != nil {
return c, err
} else if b.Valid {
Expand Down
23 changes: 23 additions & 0 deletions pkg/sigv4/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package sigv4

const (
// Amazon Managed Service for Prometheus
awsServiceName = "aps"

signingAlgorithm = "AWS4-HMAC-SHA256"

authorizationHeaderKey = "Authorization"
amzDateKey = "X-Amz-Date"

// emptyStringSHA256 is the hex encoded sha256 value of an empty string
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`

// timeFormat is the time format to be used in the X-Amz-Date header or query parameter
timeFormat = "20060102T150405Z"

// shortTimeFormat is the shorten time format used in the credential scope
shortTimeFormat = "20060102"

// contentSHAKey is the SHA256 of request body
contentSHAKey = "X-Amz-Content-Sha256"
)
Loading