スプレッドシートをサービスアカウントから作成


サービスアカウントを用いて、スプレッドシートなど、google driveに存在するファイルの作成や操作をしたかった。その際、ユーザーからも閲覧や編集したい場合があるのでそのあたりの設定も行った

操作自体は単純であるが、googleのドキュメントを読み解くのは時間がかかるので手順を残しておく

権限を持つアカウントの種類として、サービスアカウントによるものはサービスアカウント、googleアカウント(@gmail.com)によるものユーザーと表記する

設定

  1. GCPプロジェクトの作成 手順は割愛
  2. Google Sheets API / Google Drive API を有効にする GCPコンソールで上記を検索すると出てくる。有効にするとそのプロジェクト以下のすべてのサービスアカウントで有効になるよう
  3. サービスアカウントの作成、json keyファイルの作成 サービスアカウントの作成、付与する権限はなくてもいいはず、keysよりjson keyファイルを作成し、ダウンロードしておく https://console.cloud.google.com/iam-admin/serviceaccounts

コード

以下gist。colaboratoryで開いて、上から順に実行していき、uploadボタンからjson keyファイルをアップロード、共有emailなどを入力して実行していくと動く、はず

スプレッドシートを作成する

シートの作成をサービスアカウントで行うことにより、サービスアカウントがオーナーとなる

実行はコードのスプレッドシートの作成とシェアのセクション参照

ユーザーのアカウントにて共有アイテムをみると表示される

spreadsheet share

フォルダを作成し、配下にスプレッドシートを作成

フォルダに対して共有設定を行うことで、フォルダ以下のファイルもユーザーに共有される。こちらのほうが運用上で実用的

フォルダのオーナーはサービスアカウント。ファイルはユーザーが作成してもサービスアカウントにも自動的に編集者の権限が付与される

実行はコードのfolderのシェアと配下にスプレッドシートを作成のセクションを参照

フォルダ以下にシートが作成される。フォルダに権限を付与しているので自動的にユーザーも編集権限を持つ

folder share

ファイルを画面から作成すると、自動的にサービスアカウントに編集権限がつく

google doc share

google workspaceなどで外部共有の設定(google driveにて共有ボタンからをアカウントや権限を設定するやつ)に、ドメインによる制限をかけている場合、サービスアカウントのドメインの許可はできない この制限の対策として、サービスアカウントをオーナーとしてファイルを作成することで、ファイルの操作を可能にすることができる

いい方法とは言えない気もするが、回避策としてはありうる様子

NG集

オーナー権限の譲渡

サービスアカウントの変更やユーザーにオーナー権限を移行したくなった際

以下のようなオーナー権限を譲渡する関数を実行したところ、403エラーが出た

def transfer_ownership_with_notification(creds: Credentials, file_id: str, new_owner_email: str):
    """
    オーナー権限を譲渡する(通知を送信し、受信者の同意を求める)
    
    Args:
        creds: サービスアカウントの認証情報(現在のオーナー)
        file_id: ファイルまたはフォルダのID
        new_owner_email: 新しいオーナーのメールアドレス
    """
    try:
        drive_service = build('drive', 'v3', credentials=creds)
        
        # オーナー権限を譲渡(通知メール送信)
        permission = {
            'type': 'user',
            'role': 'owner',
            'emailAddress': new_owner_email
        }
        
        result = drive_service.permissions().create(
            fileId=file_id,
            body=permission,
            transferOwnership=True,
            sendNotificationEmail=True,  # 通知メールを送信
            emailMessage=f"Google Driveファイルのオーナー権限を譲渡します。承認してください。"
        ).execute()
        
        print(f"オーナー権限譲渡の通知を {new_owner_email} に送信しました。")
        print("受信者が承認するまで、オーナー権限は譲渡されません。")
        print(f"権限ID: {result.get('id')}")
        
        return result
        
    except Exception as e:
        print(f"エラーが発生しました: {e}")
        return None
'Consent is required to transfer ownership of a file to another user.', 'domain': 'global', 'reason': 'consentRequiredForOwnershipTransfer'}]
 

issue trackerはあるけど、対応されてない。不要になったらサービスアカウント経由で消すしかなさそ

https://www.reddit.com/r/node/comments/ucki1i/google_api_googlesheet_how_to_transfer_ownership/

参考

共有設定のロール

外部共有の制限方法