diff --git a/handler/proxy_client.go b/handler/proxy_client.go index 7b670ab..6b27977 100644 --- a/handler/proxy_client.go +++ b/handler/proxy_client.go @@ -24,7 +24,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/signer/v4" + v4 "github.com/aws/aws-sdk-go/aws/signer/v4" log "github.com/sirupsen/logrus" ) @@ -35,12 +35,13 @@ type Client interface { // ProxyClient implements the Client interface type ProxyClient struct { - Signer *v4.Signer - Client Client + Signer *v4.Signer + Client Client StripRequestHeaders []string SigningNameOverride string - HostOverride string - RegionOverride string + HostOverride string + RegionOverride string + LogFailedRequest bool } func (p *ProxyClient) sign(req *http.Request, service *endpoints.ResolvedEndpoint) error { @@ -144,9 +145,16 @@ func (p *ProxyClient) Do(req *http.Request) (*http.Response, error) { return nil, err } - if log.GetLevel() == log.DebugLevel && resp.StatusCode >= 400 { + if (p.LogFailedRequest || log.GetLevel() == log.DebugLevel) && resp.StatusCode >= 400 { b, _ := ioutil.ReadAll(resp.Body) - log.WithField("message", string(b)).Error("error proxying request") + log.WithField("request", fmt.Sprintf("%s %s", proxyReq.Method, proxyReq.URL)). + WithField("status_code", resp.StatusCode). + WithField("message", string(b)). + Error("error proxying request") + + // Need to "reset" the response body because we consumed the stream above, otherwise caller will + // get empty body. + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) } return resp, nil diff --git a/main.go b/main.go index 68bae3b..471fe8d 100644 --- a/main.go +++ b/main.go @@ -29,14 +29,16 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/aws/signer/v4" + v4 "github.com/aws/aws-sdk-go/aws/signer/v4" log "github.com/sirupsen/logrus" "gopkg.in/alecthomas/kingpin.v2" ) var ( - debug = kingpin.Flag("verbose", "enable additional logging").Short('v').Bool() - port = kingpin.Flag("port", "port to serve http on").Default(":8080").String() + debug = kingpin.Flag("verbose", "Enable additional logging, implies all the log-* options").Short('v').Bool() + logFailedResponse = kingpin.Flag("log-failed-requests", "Log 4xx and 5xx response body").Bool() + logSinging = kingpin.Flag("log-signing-process", "Log sigv4 signing process").Bool() + port = kingpin.Flag("port", "Port to serve http on").Default(":8080").String() strip = kingpin.Flag("strip", "Headers to strip from incoming request").Short('s').Strings() roleArn = kingpin.Flag("role-arn", "Amazon Resource Name (ARN) of the role to assume").String() signingNameOverride = kingpin.Flag("name", "AWS Service to sign for").String() @@ -45,6 +47,14 @@ var ( disableSSLVerification = kingpin.Flag("no-verify-ssl", "Disable peer SSL certificate validation").Bool() ) +type awsLoggerAdapter struct { +} + +// Log implements aws.Logger.Log +func (awsLoggerAdapter) Log(args ...interface{}) { + log.Info(args...) +} + func main() { kingpin.Parse() @@ -87,7 +97,12 @@ func main() { credentials = session.Config.Credentials } - signer := v4.NewSigner(credentials) + signer := v4.NewSigner(credentials, func(s *v4.Signer) { + if *logSinging || *debug { + s.Logger = awsLoggerAdapter{} + s.Debug = aws.LogDebugWithSigning + } + }) log.WithFields(log.Fields{"StripHeaders": *strip}).Infof("Stripping headers %s", *strip) log.WithFields(log.Fields{"port": *port}).Infof("Listening on %s", *port) @@ -101,6 +116,7 @@ func main() { SigningNameOverride: *signingNameOverride, HostOverride: *hostOverride, RegionOverride: *regionOverride, + LogFailedRequest: *logFailedResponse, }, }), )