AWS SDK for GoでS3のPre-Signed URL(事前署名付きURL)を発行する

(以前Qiitaに書いた記事ですがブログ開設に伴い移動させました。)

Pre-Signed URL(事前署名付きURL)とは

署名付き URL を受け取った相手は誰でも、そのオブジェクトにアクセスできるようになります。たとえば、プライベートのバケット内にプライベートの動画を格納している場合は、署名付き URL を生成することで、その動画を他ユーザーと共有できます。

docs.aws.amazon.com

URLさえ漏れなければURLを知っているユーザーだけにアクセスさせることが出来るようです。
特定の人だけにファイルをダウンロードさせたい時などに使えそうですね。
ExpiredAtを指定できるのでURLの有効期限も実装できそうです。

作ってみる

presignurl-goという名前のbucketにアップロード済みのtest.txtに5分間だけアクセスできるURLを発行してみましょう。

環境

Go: go version go1.9.4 linux/amd64
(以前別所に書いた記事のリライトなのでバージョンは古いままですが投稿時現在最新の1.12系でも変わらないと思います)

コード

package main

import (
        "fmt"
        "time"

        "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/aws/aws-sdk-go/service/s3"
)

func main() {
        awsCredential := AWSCredential{
                AccessKey:       "ACCESSKEY",
                SecretAccessKey: "SECRETACCESSKEY",
                Region:          "ap-northeast-1",
                Bucket:          "presignurl-go",
        }
        signedURL, err := awsCredential.CreateSignedURL("test.txt")
        if err != nil {
            fmt.Printf("%#v\n", err)
        }
        fmt.Println(signedURL)
}

type AWSCredential struct {
        AccessKey       string
        SecretAccessKey string
        Region          string
        Bucket          string
}

func (a *AWSCredential) CreateSignedURL(filename string) (string, error) {
        session, err := session.NewSession(&aws.Config{
                Credentials: credentials.NewStaticCredentials(a.AccessKey, a.SecretAccessKey, ""),
                Region:      aws.String(a.Region),
        })
        if err != nil {
                return "", err
        }

        client := s3.New(session)
        req, _ := client.GetObjectRequest(&s3.GetObjectInput{
                Bucket: aws.String(a.Bucket),
                Key:    aws.String(filename),
        })
        url, err := req.Presign(5 * time.Minute)
        if err != nil {
                return "", err
        }
        return url, nil
}

実行結果

$ go run main.go

実行してこんなかんじのURLが表示されたらPre-Signed URLの発行は成功です。

https://presignurl-go.s3.ap-northeast-1.amazonaws.com/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ACCESSKEY%2F20180720%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20180720T143921Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=SIGNATURE

ブラウザのアドレスバーに投げ込んでみるとアップロードしたtest.txtの内容が表示されました。
ちなみにprivate bucketなので署名無しURLや期限切れのPre-Signed URLを開くと下記のようなことを言われます。

This XML file does not appear to have any style information associated with it. The document tree is shown below.

雑ですが一旦これでよしとする。

これならAWS S3 CLIのpresignコマンドでいいな。乙。