From 3927223bb06281673304af8d3d7d2e02d58036c3 Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Fri, 23 Jun 2023 16:11:57 +0300 Subject: [PATCH] [#131] authmate: Add generate-presigned-url cobra cmd Signed-off-by: Denis Kirillov --- .../modules/generate-presigned-url.go | 108 ++++++++++++++++++ cmd/s3-authmate/modules/root.go | 3 + 2 files changed, 111 insertions(+) create mode 100644 cmd/s3-authmate/modules/generate-presigned-url.go diff --git a/cmd/s3-authmate/modules/generate-presigned-url.go b/cmd/s3-authmate/modules/generate-presigned-url.go new file mode 100644 index 00000000..5c677378 --- /dev/null +++ b/cmd/s3-authmate/modules/generate-presigned-url.go @@ -0,0 +1,108 @@ +package modules + +import ( + "encoding/json" + "fmt" + "os" + "time" + + "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var generatePresignedURLCmd = &cobra.Command{ + Use: "generate-presigned-url", + Short: "Generate presigned url using AWS credentials", + Long: `Generate presigned url using AWS credentials.Credentials must be placed in ~/.aws/credentials. +You provide profile to load using --profile flag or explicitly provide credentials and region using +--aws-access-key-id, --aws-secret-access-key, --region. +Note to override credentials you must provide both access key and secret key.`, + Example: `frostfs-s3-authmate generate-presigned-url --method put --bucket my-bucket --object my-object --endpoint http://localhost:8084 --lifetime 12h --region ru --aws-access-key-id ETaA2CadPcA7bAkLsML2PbTudXY8uRt2PDjCCwkvRv9s0FDCxWDXYc1SA1vKv8KbyCNsLY2AmAjJ92Vz5rgvsFCy --aws-secret-access-key c2d65ef2980f03f4f495bdebedeeae760496697880d61d106bb9a4e5cd2e0607`, + RunE: runGeneratePresignedURLCmd, +} + +const defaultPresignedLifetime = 12 * time.Hour + +const ( + endpointFlag = "endpoint" + bucketFlag = "bucket" + objectFlag = "object" + methodFlag = "method" + profileFlag = "profile" + regionFlag = "region" + awsAccessKeyIDFlag = "aws-access-key-id" + awsSecretAccessKeyFlag = "aws-secret-access-key" +) + +func initGeneratePresignedURLCmd() { + generatePresignedURLCmd.Flags().Duration(lifetimeFlag, defaultPresignedLifetime, "Lifetime of presigned URL. For example 50h30m (note: max time unit is an hour so to set a day you should use 24h).\nIt will be ceil rounded to the nearest amount of epoch.") + generatePresignedURLCmd.Flags().String(endpointFlag, "", "S3 gateway endpoint") + generatePresignedURLCmd.Flags().String(bucketFlag, "", "Bucket name to perform action") + generatePresignedURLCmd.Flags().String(objectFlag, "", "Object name to perform action") + generatePresignedURLCmd.Flags().String(methodFlag, "", "HTTP method to perform action") + generatePresignedURLCmd.Flags().String(profileFlag, "", "AWS profile to load") + generatePresignedURLCmd.Flags().String(regionFlag, "", "AWS region to use in signature (default is taken from ~/.aws/config)") + generatePresignedURLCmd.Flags().String(awsAccessKeyIDFlag, "", "AWS access key id to sign the URL (default is taken from ~/.aws/credentials)") + generatePresignedURLCmd.Flags().String(awsSecretAccessKeyFlag, "", "AWS secret access key to sign the URL (default is taken from ~/.aws/credentials)") + + _ = generatePresignedURLCmd.MarkFlagRequired(endpointFlag) + _ = generatePresignedURLCmd.MarkFlagRequired(bucketFlag) + _ = generatePresignedURLCmd.MarkFlagRequired(objectFlag) +} + +func runGeneratePresignedURLCmd(*cobra.Command, []string) error { + var cfg aws.Config + + if region := viper.GetString(regionFlag); region != "" { + cfg.Region = ®ion + } + accessKeyID := viper.GetString(awsAccessKeyIDFlag) + secretAccessKey := viper.GetString(awsSecretAccessKeyFlag) + + if accessKeyID != "" && secretAccessKey != "" { + cfg.Credentials = credentials.NewStaticCredentialsFromCreds(credentials.Value{ + AccessKeyID: accessKeyID, + SecretAccessKey: secretAccessKey, + }) + } + + sess, err := session.NewSessionWithOptions(session.Options{ + Config: cfg, + Profile: viper.GetString(profileFlag), + SharedConfigState: session.SharedConfigEnable, + }) + if err != nil { + return fmt.Errorf("couldn't get aws credentials: %w", err) + } + + reqData := auth.RequestData{ + Method: viper.GetString(methodFlag), + Endpoint: viper.GetString(endpointFlag), + Bucket: viper.GetString(bucketFlag), + Object: viper.GetString(objectFlag), + } + presignData := auth.PresignData{ + Service: "s3", + Region: *sess.Config.Region, + Lifetime: viper.GetDuration(lifetimeFlag), + SignTime: time.Now().UTC(), + } + + req, err := auth.PresignRequest(sess.Config.Credentials, reqData, presignData) + if err != nil { + return err + } + + res := &struct{ URL string }{ + URL: req.URL.String(), + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + enc.SetEscapeHTML(false) + return enc.Encode(res) +} diff --git a/cmd/s3-authmate/modules/root.go b/cmd/s3-authmate/modules/root.go index b42f9d1a..fa34ade8 100644 --- a/cmd/s3-authmate/modules/root.go +++ b/cmd/s3-authmate/modules/root.go @@ -59,4 +59,7 @@ GoVersion: {{ runtimeVersion }} rootCmd.AddCommand(obtainSecretCmd) initObtainSecretCmd() + + rootCmd.AddCommand(generatePresignedURLCmd) + initGeneratePresignedURLCmd() }