post Image
GAE/GoでGCSのコンテンツにアクセスするための署名付きリンクを生成する。

概要

前回の記事でGAE/GoからGCSのコンテンツにアクセスする時のコードがとても良くなかった。
それを解決するために一定時間アクセスが可能になる署名付きリンクを生成し、それをクライアントに渡す。というコードを書いた。

前回は何が悪かったのか

リソースを一瞬で消費する
AppEngine上で画像を展開して、それをリクエストしてきたクライアントに画像ファイルで渡す。というコードになっていた。
これは例えば3MBのファイルに1000リクエスト来たら3GB消費するということになっているのでメモリやプロセスを無駄に消費してしまう。

遅い
1つの画像をクライアントに渡すのに2回ロードが必要になる。
・GCSからAppEngineでロード
・AppEngineからクライアントでロード
とても効率が悪い。

解決策

署名付きリンクを生成する。
その上でAppEngineはクライアントに(画像の代わりに)GCSにアクセスができる署名付きリンクを渡してあげる。
これを行うことで、AppEngineはURL文字列を返すだけになるのでとても安価な処理になる。

また、1つの画像をクライアントに渡すまで、AppEngineでのロードが必要なくなったのでその分早くなった。

署名付きリンクとは

https://cloud.google.com/storage/docs/access-control/signed-urls

これは、バケットとオブジェクトに対するクエリ文字列認証のためのメカニズムです。署名付き URL は、時間制限のある読み取りや書き込みのアクセス権を、Google アカウントを持っているかどうかにかかわらず、URL を知っている全員に許可するための手段です

つまりこの場合、GCSのコンテンツに対して一定期間だけアクセス可能になるURLを発行し、そのURLが有効な間は誰でもアクセスができるというもの。
注意点としては、クライアントがこのURLをキャッシュするような場合は有効期限が切れてしまいアクセスできない可能性がある点。

署名付きリンクを生成するコード

GAE/GoでWebフレームワークはginを使っています。

main.go
func GetPageImageOfSignedURL(g *gin.Context) {
    signedURL, err := GCSManager.GetSignedUrl(g)
    if err != nil {
        g.String(http.StatusBadRequest, err.Error())
    }
    g.String(http.StatusOK, signedURL)
}
GCSManager.go
func GetSignedUrl(g *gin.Context) (url string, err error) {
    c := appengine.NewContext(g.Request)
    //Defaultのバケット名を取得する
    bucketName, err := file.DefaultBucketName(c)
    if err != nil {
        return url, err
    }
    //fileNameは例えば[bucket名]/foo/bar.jpgというようなディレクトリ構造を持つファイルの場合は"foo/bar.jpg"と指定する。
    fileName := "foo/bar.jpg"
    //ここでExpireする時間を決める。(今回は60秒とした。)
    expires := time.Now().Add(time.Second * 60)
    //[projectID]@appspot.gserviceaccount.comを取得する。こうしなくてもstring直書きでも問題ない。
    acc, _ := appengine.ServiceAccount(c)

    //SignedURLを取得する(Optionについては後述)
    url, err = storage.SignedURL(bucketName, fileName, &storage.SignedURLOptions{
        GoogleAccessID: acc,
        SignBytes: func(b []byte) ([]byte, error) {
            _, signedBytes, err := appengine.SignBytes(c, b)
            return signedBytes, err
        },
        Method:  "GET",
        Expires: expires,
    })
    //URL文字列を返す。
    return url, err
}

storage.SignedURLOptionsについて

参考:https://cloud.google.com/storage/docs/access-control/signed-urls

GoogleAccessID:必須
[projectID]@appspot.gserviceaccount.com を指定する。
PrivateKey または SignBytes:どちらかが必須
今回はSignBytes関数を利用した。
(SignBytes関数はこのアプリケーションがGAE上で動いている時に使えるGAE内部の認証関数とのこと)

PrivateKeyはGoogleDeveloperConsoleからClientIDを作り、そこからP12証明書を生成する。
それをPEMファイルに変換し、それをByteのスライスに変換してPrivateKeyに代入する。
これに関しては自分はやっていないので詳しい解説はここ参照
Method:必須
署名付きURLで使用するHTTP動詞。
Expires:必須
署名の有効期限が切れるタイムスタンプ。UNIXTimeで表現する。

結果

tempurl.
https://storage.googleapis.com/bucketname/foo/bar.jpg?Expires=1485049086&GoogleAccessId=hogeproject%40appspot.gserviceaccount.com&Signature=ZNlN6NzfPb6DiR%2FxOAjUN4LF7f7pkJEusZ3zr8EEnrofquPCNUtd%2FXek2ur9gKA8sEGBbzMMp%2BKzMS6vyBJl9bDCKf6XnL2N3ZBnx7W%2B1anhCXajpgwAsH6FVxYN9OD1EOqgtTlZxv3tyRfvyaipfrtB1d2Ip84gdxVVTsWVAhk2SmqTehNJor94LW%2BrkyBpn%2Bm3M%2BlRGcx9ZAu8BPuywIGyt%2BW4G8ve6cXJzzpJBJYnosJwKx047%2BSoeTdvk2p%2BLyR%2BfyHhS6OV7RDPDaWX4YGXxcw8v2Q0Pnp2iOs5kegMZOiKup1NyqhRHFNo9tX8C%2FPQ0b38FGQAlcOREheFIA%3D%3D

のようなURLが生成される。

60秒間はアクセスできる。しかし、60秒以上経つと

Expired.xml
<Error>
<Code>ExpiredToken</Code>
<Message>The provided token has expired.</Message>
<Details>Request has expired: 1485049363</Details>
</Error>

という表示がされる(ブラウザで確認したもの)


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。