Background
By default, all S3 objects are private. Only the object owner has permission to access them. However, the object owner can optionally share objects with others by creating a presigned URL, using their own security credentials, to grant time-limited permission to download the objects.
Providing a presigned URL is a secure method to provide access to objects in your S3 bucket without providing permanent keys or providing access to your bucket.
This article will review how to get resigned URls for downloading and uploading objects to an s3 bucket with Go AWS SDK v2. The s3 Go package documentation can be found in this link.
Please refer to AWS documentation for more information about using presigned URLs and policy requirements.
Go AWS SDK v2
AWS offers SDK v2 for Golang to call AWS APIs.
The main package for AWS services is github.com/aws/aws-sdk-go-v2/aws and the SDK includes a package for each AWS service.
In this example, we’ll use the aws package and the s3 package. The import should look like the following:
import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
All code examples assume that the config object is created as in this example:
func newConfig() aws.Config {
cfg, err := config.LoadDefaultConfig(context.Background(),
config.WithRegion(regionName),
config.WithSharedConfigProfile(profileName))
if err != nil {
log.Fatal(err)
}
return cfg
}
The functions discussed in this article get aws.Config as the input parameter.
S3 PresignClient
PresignClient is the client that provided the different S3 presign APIs. To init the client, you need to provide an s3 client (created by the functions s3.New or s3.NewFromConfig).
PresignClient provides multiple APIs: PresignDeleteBucket, PresignDeleteObject, PresignGetObject, PresignHeadBucket, PResignHeadObject, PresignPutObject, and PresignUploadPart.
We’ll review the two functions, PresignGetObject and PresignPutObject. Please refer to the documentation for all other functions in this link https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#PresignClient.
Get Object
Create a Presign URL for the Get Object method
func getPresignURL(cfg aws.Config) string {
s3client := s3.NewFromConfig(cfg)
presignClient := s3.NewPresignClient(s3client)
presignedUrl, err := presignClient.PresignGetObject(context.Background(),
&s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(keyName),
},
s3.WithPresignExpires(time.Minute*15))
if err != nil {
log.Fatal(err)
}
return presignedUrl.URL
}
To provide input parameters to the PresignGetObject function, we use the struct s3.GetObjectInput. Bucket and Key are required parameters, as this function provides presigned URL for the specific key in the bucket.
The function s3.WithPresignExpires function will take the duration for the url’s TTL.
The example above returns a presigned URL to get the object in the browser. To create a presigned URL for an object to download it directly from your browser, add Content-Disposition header to the input parameters as follows:
presignedUrl, err := presignClient.PresignGetObject(context.Background(),
&s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(keyName),
ResponseContentDisposition: aws.String("attachment"),
},
s3.WithPresignExpires(time.Minute*15))
Put Object
Create Presign URL for Put Object method (upload object). Use the PresignPutObject method. Set the key object name as the object name to assign to the uploaded file.
func putPresignURL(cfg aws.Config) string {
s3client := s3.NewFromConfig(cfg)
presignClient := s3.NewPresignClient(s3client)
presignedUrl, err := presignClient.PresignPutObject(context.Background(),
&s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectName),
},
s3.WithPresignExpires(time.Minute*15))
if err != nil {
log.Fatal(err)
}
return presignedUrl.URL
}
To provide input parameters to the PresignPutObject function, we use the struct s3.PutObjectInput. Bucket and Key are required parameters, as this function provides a presign URL for the specific key in the bucket.
Upload a file using the provided presigned URL
To upload a file to the S3 bucket with the presign URL, use the PUT method (the POST method will return an HTTP error).
Here is an example of uploading a file to the URL returned by the putPresignURL function above:
func uploadFile(filePath string, url string) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
buffer := bytes.NewBuffer(nil)
if _, err := io.Copy(buffer, file); err != nil {
return err
}
request, err := http.NewRequest(http.MethodPut, url, buffer)
if err != nil {
return err
}
request.Header.Set("Content-Type", "multipart/form-data")
client := &http.Client{}
_, err = client.Do(request)
return err
}