GCS上のコンテンツを自分のGAEアプリケーションからしかアクセスできないようにする

この記事は最終更新日から3年以上が経過しています。

2017/01/20追記

コメントにて

App EngineはService Accountはデフォルトで、ProjectのEditorを持っている

というご指摘をいただきました。やり直してみたらたしかにその通りでした。
おそらくいろいろいじってるうちに設定が消えるなどしてしまったのかも…。

この記事はACLを再設定する方法ということにします。

ただ、それにしても最後のGCSから画像をロードするサンプルコードで、GAEのメモリめっちゃ食う実装をしてたので改善策を新たな記事に書きます。テキストなどの小さいファイルのものはこれでも特に問題なさそうなのでこれで問題ないかと思います。

元記事

GoogleAppEngineからGCS上のコンテンツをアクセスするには、コードでGCSのライブラリを使う必要があります。
その方法は後で紹介するとして、まずはGCS上のコンテンツのアクセス制御を設定しなければなりません。

何も考えずにGAEからGCS上のコンテンツにアクセスできるようにすると
CropperCapture[243].png
こんな感じで公開リンクとして設定してやれば、公開用のURLが発行されるので楽にできます。

ただ、セキュリティの事を考えるとこれはあまり良くないですね。
セキュリティ以外にも、GCSはネットワーク出力に金がかかるので知らんうちに課金が発生してしまうかも…なんて恐怖に怯えることになります。

というわけで今回は公開リンクを設定せず、自分のGAEアプリケーションからのみコンテンツにアクセス出来る方法を紹介します。

はじめに

前提として
・GAEアプリケーションはデプロイ済み
・GCSにはBucketが存在してなんらかのファイルがあるものとします。
・gsutilが使える状態

この前提の中でわからないことがある人は、以下の記事を見ると良いと思います。
(参照:http://qiita.com/sinmetal/items/20fc9ae601161291b16e

自分のGAEアプリケーションのサービスアカウントを確認する

IAMと管理を開きます。↓
https://console.cloud.google.com/iam-admin

さらに横のタブにあるIAMを開きます。
CropperCapture[244].png

この中で「App Engine default service account」を探します
別にDefaultでなくてもいいと思いますが今回はわかりやすいので。

おそらく
{{projectID}}@appspot.gserviceaccount.comという文字列になっているのでそれをメモしておいて下さい。

GCSのバケットとファイルにアクセス制御を設定する

GCSのアクセス制御はACLを設定することによって成ります。

アクセス制御リスト(ACL)とは、オブジェクトを他のユーザーと共有したり、自分のバケットとオブジェクトへのアクセスを他のユーザーに許可したりするためのメカニズムです。
https://cloud.google.com/storage/docs/access-control/lists

このACLはGCSのコンソールで1つずつ権限を付与できますが、それはあまりにも面倒だし僕の場合は1万個ほどのファイルに権限を付与したいのでやってられませんね。

なのでそこら辺を上手いことやってくれるgsutilを使います。

アクセス制御には具体的には以下のようなコマンドを使います。

#バケットに対してアクセス制御をする時
gsutil acl ch -u {{projectID}}@appspot.gserviceaccount.com:R gs://{{ACLを編集したいbucket名}}

#バケットの中のファイルに対してアクセス制御をする時
gsutil -m acl ch -u {{projectID}}@appspot.gserviceaccount.com:R gs://{{ACLを編集したいbucket名}}/foo/bar.jpg

-mオプション:
マルチスレッドで権限付与をしてくれます。多数のファイルが有る時にかなり有効

acl ch:
Linuxのchmodのような機能。ACLを変更する。

-uオプション:
ここにある通り、ユーザをIDやEmailで定めるようにコマンドのフォーマットを指定するオプション

{{projectID}}@appspot.gserviceaccount.com:R:
AppEngineのサービスアカウントに対してR(Read=読み取り)を許可している。書き込みを許可する時はW。

gs://{{ACLを編集したいbucket名}}/foo/bar.jpg:
バケットもしくはファイルを指定する。
gs://{{ACLを編集したいbucket名}}/*.jpg
とやればバケット直下の全てのJPGファイルを対象とできる。


コマンドが完了すれば下のような権限が設定されているはず。
CropperCapture[247].png

まぁ困ったときは公式のドキュメントを見るのが良いですね。
https://cloud.google.com/storage/docs/gsutil/commands/acl

注意点

既に公開リンクに設定してあるファイルに↑のコマンドを設定しても勝手に非公開になるわけではありません。設定が追加されるだけなので。
なので一度非公開化してからgsutilでGAEアプリケーションのみを許可するようにしたほうが良いかなと思います。

#例
gsutil acl set private gs://{{bucket名}}/*.jpg

GAE/Goからファイルにアクセスする方法

おまけなのでざっくりと書きます。

FileManager.go
func GetImageData(g *gin.Context) (imageBytes []byte, err error) {
    c := appengine.NewContext(g.Request)
    bucketName, err := file.DefaultBucketName(c)
    if err != nil {
        return imageBytes, err
    }
    client, err := storage.NewClient(c)
    if err != nil {
        return imageBytes, err
    }

    reader, err := client.Bucket(bucketName).Object("test/ds.PNG").NewReader(c)
    if err != nil {
        return imageBytes, err
    }
    defer reader.Close()
    imageBytes, error := ioutil.ReadAll(reader)
    return imageBytes, error

}
main.go
func GetImage(g *gin.Context) {

    imageBytes, err := FileManager.GetImageData(g)
    if err != nil {
        g.String(http.StatusBadRequest, err.Error())
    }
    g.Data(200, "image/jpeg", imageBytes)
}

これでGCS上のコンテンツは自分とGAEからのみしかアクセスを受付ないので脆弱性が少し減ったのではないかと思います。
次はGAEのRESTfulAPIの設計とか学習したらそこら辺の話を書きます。

以上です。

ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
コメント
この記事にコメントはありません。
あなたもコメントしてみませんか :)
すでにアカウントを持っている方は
ユーザーは見つかりませんでした