[#339] Fix logging in authmate [pre]sign command

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2024-11-27 11:31:53 +03:00
parent 7bf31bea18
commit ea714c2e9e
6 changed files with 54 additions and 31 deletions

View file

@ -142,10 +142,6 @@ func (c *Center) parseAuthHeader(authHeader string, headers http.Header) (*AuthH
default: default:
return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), authHeader) return nil, fmt.Errorf("%w: %s", apierr.GetAPIError(apierr.ErrAuthorizationHeaderMalformed), authHeader)
} }
// AWS4-ECDSA-P256-SHA256
// Credential=2XGRML5EW3LMHdf64W2DkBy1Nkuu4y4wGhUj44QjbXBi05ZNvs8WVwy1XTmSEkcVkydPKzCgtmR7U3zyLYTj3Snxf/20240326/s3/aws4_request,
// SignedHeaders=amz-sdk-invocation-id;amz-sdk-request;host;x-amz-content-sha256;x-amz-date;x-amz-region-set,
// Signature=3044022006a2bc760140834101d0a79667d6aa75768c1a28e9cafc8963484d0752a6c6050220629dc06d7d6505e1b1e2a5d1f974b25ba32fdffc6f3f70dc4dda31b8a6f7ea2b
return &AuthHeader{ return &AuthHeader{
AccessKeyID: submatches["access_key_id"], AccessKeyID: submatches["access_key_id"],
@ -487,20 +483,19 @@ func SignStr(secret, service, region string, t time.Time, strToSign string) stri
return hex.EncodeToString(signature) return hex.EncodeToString(signature)
} }
func SignStrV4A(cred aws.Credentials, strToSign string) (string, error) { func SignStrV4A(ctx context.Context, cred aws.Credentials, strToSign string) (string, error) {
hash := sha256.New()
hash.Write([]byte(strToSign))
credAdapter := v4a.SymmetricCredentialAdaptor{ credAdapter := v4a.SymmetricCredentialAdaptor{
SymmetricProvider: credentials.NewStaticCredentialsProvider(cred.AccessKeyID, cred.SecretAccessKey, ""), SymmetricProvider: credentials.NewStaticCredentialsProvider(cred.AccessKeyID, cred.SecretAccessKey, ""),
} }
creds, err := credAdapter.RetrievePrivateKey(context.Background()) // because of using StaticCredentialsProvider creds, err := credAdapter.RetrievePrivateKey(ctx)
if err != nil { if err != nil {
// no error is expected return "", err
panic(err)
} }
hash := sha256.New()
hash.Write([]byte(strToSign))
sig, err := creds.PrivateKey.Sign(rand.Reader, hash.Sum(nil), crypto.SHA256) sig, err := creds.PrivateKey.Sign(rand.Reader, hash.Sum(nil), crypto.SHA256)
if err != nil { if err != nil {
return "", err return "", err

View file

@ -13,6 +13,7 @@ import (
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws"
utils "github.com/trailofbits/go-fuzz-utils" utils "github.com/trailofbits/go-fuzz-utils"
"go.uber.org/zap"
) )
const ( const (
@ -60,7 +61,7 @@ func DoFuzzAuthenticate(input []byte) int {
SignTime: time.Now().UTC(), SignTime: time.Now().UTC(),
} }
req, err := PresignRequest(context.Background(), awsCreds, reqData, presignData) req, err := PresignRequest(context.Background(), awsCreds, reqData, presignData, zap.NewNop())
if req == nil { if req == nil {
return fuzzFailExitCode return fuzzFailExitCode
} }

View file

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -16,6 +15,7 @@ import (
"github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/smithy-go/encoding/httpbinding" "github.com/aws/smithy-go/encoding/httpbinding"
"github.com/aws/smithy-go/logging" "github.com/aws/smithy-go/logging"
"go.uber.org/zap"
) )
type RequestData struct { type RequestData struct {
@ -34,7 +34,7 @@ type PresignData struct {
} }
// PresignRequest forms pre-signed request to access objects without aws credentials. // PresignRequest forms pre-signed request to access objects without aws credentials.
func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestData, presignData PresignData) (*http.Request, error) { func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestData, presignData PresignData, log *zap.Logger) (*http.Request, error) {
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false)) urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil) req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
if err != nil { if err != nil {
@ -49,6 +49,8 @@ func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestD
signer := v4.NewSigner(func(options *v4.SignerOptions) { signer := v4.NewSigner(func(options *v4.SignerOptions) {
options.DisableURIPathEscaping = true options.DisableURIPathEscaping = true
options.LogSigning = true
options.Logger = &logWrapper{log: log}
}) })
signedURI, _, err := signer.PresignHTTP(ctx, creds, req, presignData.Headers[AmzContentSHA256], presignData.Service, presignData.Region, presignData.SignTime) signedURI, _, err := signer.PresignHTTP(ctx, creds, req, presignData.Headers[AmzContentSHA256], presignData.Service, presignData.Region, presignData.SignTime)
@ -64,7 +66,7 @@ func PresignRequest(ctx context.Context, creds aws.Credentials, reqData RequestD
} }
// PresignRequestV4a forms pre-signed request to access objects without aws credentials. // PresignRequestV4a forms pre-signed request to access objects without aws credentials.
func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData PresignData) (*http.Request, error) { func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData PresignData, log *zap.Logger) (*http.Request, error) {
urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false)) urlStr := fmt.Sprintf("%s/%s/%s", reqData.Endpoint, httpbinding.EscapePath(reqData.Bucket, false), httpbinding.EscapePath(reqData.Object, false))
req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil) req, err := http.NewRequest(strings.ToUpper(reqData.Method), urlStr, nil)
if err != nil { if err != nil {
@ -76,12 +78,12 @@ func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData Pr
} }
req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z")) req.Header.Set(AmzDate, presignData.SignTime.Format("20060102T150405Z"))
req.Header.Set(AmzExpires, strconv.Itoa(int(presignData.Lifetime.Seconds()))) req.Header.Set(AmzExpires, strconv.FormatFloat(presignData.Lifetime.Round(time.Second).Seconds(), 'f', 0, 64))
signer := v4a.NewSigner(func(options *v4a.SignerOptions) { signer := v4a.NewSigner(func(options *v4a.SignerOptions) {
options.DisableURIPathEscaping = true options.DisableURIPathEscaping = true
options.LogSigning = true options.LogSigning = true
options.Logger = logging.NewStandardLogger(os.Stdout) options.Logger = &logWrapper{log: log}
}) })
credAdapter := v4a.SymmetricCredentialAdaptor{ credAdapter := v4a.SymmetricCredentialAdaptor{
@ -97,7 +99,21 @@ func PresignRequestV4a(cred aws.Credentials, reqData RequestData, presignData Pr
return nil, fmt.Errorf("presign: %w", err) return nil, fmt.Errorf("presign: %w", err)
} }
fmt.Println(presignedURL)
return http.NewRequest(reqData.Method, presignedURL, nil) return http.NewRequest(reqData.Method, presignedURL, nil)
} }
type logWrapper struct {
log *zap.Logger
}
func (l *logWrapper) Logf(classification logging.Classification, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
switch classification {
case logging.Warn:
l.log.Warn(msg)
case logging.Debug:
l.log.Debug(msg)
default:
l.log.Info(msg)
}
}

View file

@ -20,6 +20,7 @@ import (
credentialsv2 "github.com/aws/aws-sdk-go-v2/credentials" credentialsv2 "github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/smithy-go/logging" "github.com/aws/smithy-go/logging"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
) )
var _ tokens.Credentials = (*credentialsMock)(nil) var _ tokens.Credentials = (*credentialsMock)(nil)
@ -83,7 +84,7 @@ func TestCheckSign(t *testing.T) {
}, },
} }
req, err := PresignRequest(ctx, awsCreds, reqData, presignData) req, err := PresignRequest(ctx, awsCreds, reqData, presignData, zaptest.NewLogger(t))
require.NoError(t, err) require.NoError(t, err)
expBox := &accessbox.Box{ expBox := &accessbox.Box{
@ -131,7 +132,7 @@ func TestCheckSignV4a(t *testing.T) {
}, },
} }
req, err := PresignRequestV4a(awsCreds, reqData, presignData) req, err := PresignRequestV4a(awsCreds, reqData, presignData, zaptest.NewLogger(t))
require.NoError(t, err) require.NoError(t, err)
req.Header.Set(ContentTypeHdr, "text/plain") req.Header.Set(ContentTypeHdr, "text/plain")

View file

@ -1,6 +1,7 @@
package modules package modules
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http" "net/http"
@ -60,6 +61,11 @@ func initGeneratePresignedURLCmd() {
} }
func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error { func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag))
defer cancel()
log := getLogger()
var ( var (
region string region string
creds aws.Credentials creds aws.Credentials
@ -68,16 +74,16 @@ func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
profile := viper.GetString(profileFlag) profile := viper.GetString(profileFlag)
if profile == "" { if profile == "" {
cfg, err := config.LoadDefaultConfig(cmd.Context()) cfg, err := config.LoadDefaultConfig(ctx)
if err != nil { if err != nil {
return wrapPreparationError(err) return wrapPreparationError(err)
} }
region = cfg.Region region = cfg.Region
if creds, err = cfg.Credentials.Retrieve(cmd.Context()); err != nil { if creds, err = cfg.Credentials.Retrieve(ctx); err != nil {
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err)) return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
} }
} else { } else {
cfg, err := config.LoadSharedConfigProfile(cmd.Context(), viper.GetString(profileFlag)) cfg, err := config.LoadSharedConfigProfile(ctx, viper.GetString(profileFlag))
if err != nil { if err != nil {
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", viper.GetString(profileFlag), err)) return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", viper.GetString(profileFlag), err))
} }
@ -117,9 +123,9 @@ func runGeneratePresignedURLCmd(cmd *cobra.Command, _ []string) error {
var req *http.Request var req *http.Request
if viper.GetBool(sigV4AFlag) { if viper.GetBool(sigV4AFlag) {
req, err = auth.PresignRequestV4a(creds, reqData, presignData) req, err = auth.PresignRequestV4a(creds, reqData, presignData, log)
} else { } else {
req, err = auth.PresignRequest(cmd.Context(), creds, reqData, presignData) req, err = auth.PresignRequest(ctx, creds, reqData, presignData, log)
} }
if err != nil { if err != nil {
return wrapBusinessLogicError(err) return wrapBusinessLogicError(err)

View file

@ -1,6 +1,7 @@
package modules package modules
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -49,22 +50,25 @@ func initSignCmd() {
} }
func runSignCmd(cmd *cobra.Command, _ []string) error { func runSignCmd(cmd *cobra.Command, _ []string) error {
ctx, cancel := context.WithTimeout(cmd.Context(), viper.GetDuration(timeoutFlag))
defer cancel()
var ( var (
region string region string
creds aws.Credentials creds aws.Credentials
) )
if profile := viper.GetString(profileFlag); profile == "" { if profile := viper.GetString(profileFlag); profile == "" {
cfg, err := config.LoadDefaultConfig(cmd.Context()) cfg, err := config.LoadDefaultConfig(ctx)
if err != nil { if err != nil {
return wrapPreparationError(err) return wrapPreparationError(err)
} }
region = cfg.Region region = cfg.Region
if creds, err = cfg.Credentials.Retrieve(cmd.Context()); err != nil { if creds, err = cfg.Credentials.Retrieve(ctx); err != nil {
return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err)) return wrapPreparationError(fmt.Errorf("couldn't get default aws credentials: %w", err))
} }
} else { } else {
cfg, err := config.LoadSharedConfigProfile(cmd.Context(), profile) cfg, err := config.LoadSharedConfigProfile(ctx, profile)
if err != nil { if err != nil {
return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", profile, err)) return wrapPreparationError(fmt.Errorf("couldn't get '%s' aws credentials: %w", profile, err))
} }
@ -106,8 +110,8 @@ func runSignCmd(cmd *cobra.Command, _ []string) error {
sigv4a := viper.GetBool(sigV4AFlag) sigv4a := viper.GetBool(sigV4AFlag)
if sigv4a { if sigv4a {
var err error var err error
if signature, err = auth.SignStrV4A(creds, data); err != nil { if signature, err = auth.SignStrV4A(ctx, creds, data); err != nil {
return wrapPreparationError(fmt.Errorf("sign v4a: %w", err)) return wrapPreparationError(fmt.Errorf("sign str v4a: %w", err))
} }
} else { } else {
signature = auth.SignStr(creds.SecretAccessKey, service, region, signTime, data) signature = auth.SignStr(creds.SecretAccessKey, service, region, signTime, data)