Help us understand the problem. What is going on with this article?

Python(boto)からサービスアカウントとキーファイル(p12)を使ってGoogle Cloud Storageにアクセスする

More than 3 years have passed since last update.

botoからGoogle Cloud Storageにアクセスする場合、s3との互換運用アクセスを有効にすることでアクセスキーとシークレットキーでアクセスすることが可能です。
http://qiita.com/itkr/items/d990e87a2540332ee0e5

ただしこの方法にはひとつ問題があります。互換運用アクセスで発行できるアクセスキーはGoogleユーザーアカウントにリンクされるため、複数人で行うプロジェクトでは不便です。そこでサービスアカウントとキーファイル(p12)でアクセスするという選択肢が出てきます。

依存ライブラリのインストール

ここではgcs-oauth2-boto-pluginというライブラリを使用します。

pip install gcs-oauth2-boto-plugin

設定ファイルの準備

サービスアカウントとキーファイルのパスを記述する設定ファイルを準備します。

ファイルの場所

デフォルトでは~/.botoを見ますが、環境変数で以下のどちらかを用意すると任意のパスを指定できます。ちなみにこれはgsutilと同じです。

  • BOTO_CONFIG (単一ファイルを指定する)
  • BOTO_PATH (:区切りで複数ファイルを指定する)

pythonで環境変数を書く場合は下のように書きます。

import os
os.environ['BOTO_CONFIG'] = '/path.to/boto_config'

必要な記述

いろいろ設定を書くことが出来ますが、今回重要なのは次の設定です

[Credentials]
gs_service_key_file = /path.to/sample-KEYFILE.p12
gs_service_client_id = sample-service-account@developer.gserviceaccount.com

[GSUtil]
default_project_id = sampleproject-994

参考:https://cloud.google.com/storage/docs/gsutil/commands/config#additional-configuration-controllable-features

実装

基本コード

import boto

bucket_name = 'bucket_name'
uri = boto.storage_uri(bucket_name, 'gs')
print uri.get_bucket()

基本的にはgcs-oauth2-boto-pluginをインストールしていればこれだけです。

解説

なぜこれだけで良いのか

botoはAuthConnectionを貼る際にPluginを導入できる仕組みを用意しています。詳細に書くとbotoの実装の多くを転載することになってしまうので省きますが、botoのauth関連のコードを見るとget_pluginという関数の呼び出しを見つけることが出来ます。

boto/plugin.py
def get_plugin(cls, requested_capability=None):
    if not requested_capability:
        requested_capability = []
    result = []
    for handler in cls.__subclasses__():
        if handler.is_capable(requested_capability):
            result.append(handler)
    return result

__subclasses__はサブクラスの一覧を表示しますが、この場合はAuthHandlerクラスを継承しているクラスの一覧になります。gcs-oauth2-boto-pluginの中のOAuth2ServiceAccountAuthというクラスがAuthHandlerを継承しているためプラグインとして認識されます。その中で設定ファイルからgs_service_key_fileなど必要な情報を取得しています。

ちなみに

自分でAuthHandlerを継承したクラスを実装し、中でconfigファイルのパスを無理矢理上書きして動的に変更することもできます。が、たぶんもっとスマートにできると思います。

from boto.auth_handler import AuthHandler
from boto.pyami.config import Config

boto_path = ''

class SpamAuth(AuthHandler):
    def __init__(self, path, config, provider):
        config = Config(path=boto_path)
        # ... 略 ...

def spam(path='/path.to/boto_config'):
    global boto_path
    boto_path = path
    bucket_name = 'bucket_name'
    uri = boto.storage_uri(bucket_name, 'gs')
    print uri.get_bucket()

なお、この際にURIクラス(この場合BucketStorageUri)は一度connectionを張るとprovider_poolというdictの中にconnectionを保持するので、connectionを切り替える場合はdel BucketStorageUri.provider_pool['gs']BucketStorageUri.provider_pool = {}のようにクリアしてあげないとダメみたいですね。

itkr
おひさま
http://itkr.github.io
colorful-board
「すべての人々に、人生が変わる出会いを」をビジョンとして、これまで出会えなかった情報と瞬時に出会うことで人々の生活をより豊かにする、新しい情報発見のためのプラットフォームを目指しています。
https://sensy.ai/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした