🌟

アカウントAPIトークンでR2 Tokenを発行してみる

2024/12/11に公開

まえがき

この記事は VR法人HIKKY Advent Calendar 2024 の 4 日目の記事です。
https://qiita.com/advent-calendar/2024/hikky

3日目は コーポレートサイトがメモリを無限に食べていたので修正した話 、5日目は Unity開発者インタビュー:Atlas化ツールの開発物語 さんがどちらも素晴らしい記事を書いてくれていますので、ぜひご覧になってください。

この記事は箸休めです。12/04 200時間目に失礼します。

背景

Cloudflareでいくつか以前記事を出させていただきました。
☆以前読んでいただいた方はありがとうございます☆

https://zenn.dev/kazu0617/articles/699ca7d354c4c0

https://zenn.dev/kazu0617/articles/4a890a4a21f867

この記事のどちらでも「API Token」を発行していますが、
実はこのAPIトークンは長らくユーザーに紐つくもののみでした。

https://dash.cloudflare.com/profile/api-tokens

また、このユーザーに紐つくトークンは作れる個数が決まっておりまして、50個以上は作れないようになっています。

そのため上の記事の様に「バケットを直接触れる権限」を上げる方毎に切ったり、アプリケーション側毎に切ったりしていると、50個の上限に引っかかることが増えてきました。

概要

APIトークンは今まで「ユーザー」に紐つくもののみだったのが、ここ最近で「アカウント」に紐付けることもできるようになりました。

https://developers.cloudflare.com/fundamentals/api/get-started/account-owned-tokens/

ただ、アカウントAPIトークンでR2のバケットごとに発行することは現状公式ドキュメントはありません。また、GUIでも「ユーザーAPIトークン」の導線しかありませんでした。

本記事では、「R2のバケットごとに制限されたAPIトークンを発行し、トークン / トークンから発行できたS3アクセスキーを利用してバケットに接続する」を、アカウントAPIトークンを利用して実施する方法を解説します。

この方法は、公式のドキュメントに記載されていない部分もあるため、独自に調査・試行した結果をベースに構築しました。

もし同じように困っている方がいればぜひ実践してみてください。

前提知識

ユーザー (User)

  • 定義: 個人を表すアカウント(メールアドレスに紐づく)。
  • 権限: 所属するアカウントやロールによって操作可能な範囲が異なる。
  • 利用例: 一人のユーザーが複数のアカウントに所属することが可能。
    User Tokenはこちらに紐つきます。トークンはユーザー毎の管理画面で確認できます。

アカウント (Account)

  • 定義: 組織やプロジェクトを表す単位。
  • 権限: 所属するユーザーにロールや権限を付与可能。
  • 利用例: 1つのアカウントに複数のユーザーが所属。
    Account Owned Tokenはこちらに紐つきます。トークンはアカウント側で確認できます。

取得する全体の流れ

  1. ユーザーAPIトークンを作成(初回のみ)
  2. R2バケットにアクセスできるアカウントAPIトークンの作成
  3. 接続設定の確認とテスト

手順

凡例:

  • account_id: 動作させたいアカウントID
    • アカウントIDはここから取得できます。
  • bucket_name: アクセスを承認したいバケット名
  • token_name: トークン名

1. ユーザーAPIトークンを作成(初回のみ)

エンドポイント: ユーザーAPIトークンの作成

  • 認証方法: ユーザーAPIキーを利用
  • Body: 以下の通り
{
    "name": "Create Additional Tokens",
    "condition": {},
    "policies": [
        {
            "effect": "allow",
            "resources": {
                "com.cloudflare.api.account.{account_id}": "*"
            },
            "permission_groups": [
                {
                    "id": "5bc3f8b21c554832afc660159ab75fa4"
                }
            ]
        }
    ]
}

2. R2バケットにアクセスできるアカウントAPIトークンの作成

次に、R2バケットに特化したアカウントAPIトークンを生成します。このトークンを使うことで、特定のバケットに対するリソース操作を許可できます。

resourcesの値は公式ドキュメントを参考に導出してください。
https://developers.cloudflare.com/r2/api/s3/tokens/#create-api-tokens-via-api

エンドポイント: アカウントAPIトークンの作成

  • 認証方法: 1で作成したユーザーAPIトークンを利用
  • Body: 以下の通り
{
    "name": "{token_name}",
    "policies": [
        {
            "effect": "allow",
            "resources": {
                "com.cloudflare.edge.r2.bucket.{account_id}_default_{bucket_name}": "*"
            },
            "permission_groups": [
                {
                    "id": "2efd5506f9c8494dacb1fa10a3e7d5b6",
                    "name": "Workers R2 Storage Bucket Item Write"
                },
                {
                    "id": "6a018a9f2fc74eb6b293b0c548f38b39",
                    "name": "Workers R2 Storage Bucket Item Read"
                }
            ]
        }
    ]
}

発行されたトークンには、IDとValueが含まれます。これらを必ずメモしておきましょう。

3. APIトークンをS3アクセスキーに変換

トークンを取得したら、R2に接続するための下準備として、APIトークンからS3アクセスキーを計算します。

公式ドキュメント:
https://developers.cloudflare.com/r2/api/s3/tokens/#get-s3-api-credentials-from-an-api-token

You can get the Access Key ID and Secret Access Key values from the response of the Create Token API:
Access Key ID: The id of the API token.
Secret Access Key: The SHA-256 hash of the API token value.
Refer to Authenticate against R2 API using auth tokens for a tutorial with JavaScript, Python, and Go examples.

こちらを参考に計算します。

  • Access Key ID: トークンのID
  • Secret Access Key: トークンのValueをSHA-256でハッシュ化し、小文字化したものを使用
    PowerShellを使ってハッシュ化する際は下の関数を回してみてください。
$token = "Token_Value"
$hash = (Get-FileHash -InputStream ([System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($token)))).Hash.ToLower()

4. 各クライアントで接続

各クライアントで接続します。

4.1. サーバードメインの確認

つい数日前のアップデートで、R2 Object StorageのOverviewから直接コピーできるようになりました!


下側の値をコピーすればOK。Cyberduckで使用する際はhttps://は消して貼り付け

Cyberduckで接続する際は下の通りになります。
サーバー: <アカウントID>.r2.cloudflarestorage.com

  • Access Key ID / Secret Access Key: [APIトークンをS3アクセスキーに変換] で確認したもの
  • パス: 接続したいバケット名を指定

情報を入力し、正常に接続できればOKです。

付与した権限グループについて

付与したpermission_groupsについてです。

ユーザーAPIトークンはここから一覧が確認できます。
https://developers.cloudflare.com/api/operations/permission-groups-list-permission-groups

アカウントAPIトークンはここから一覧が確認できます。
https://developers.cloudflare.com/api/operations/account-api-tokens-list-permission-groups

ただ、実際の返答としてはユーザーAPIトークンの権限リストとアカウントAPIトークンの権限リストはほぼ同じなため、ユーザーAPIトークンで返ってきた結果を元に権限グループを設定しても現状問題ないと思いました。


WinMergeで差分確認。ユーザーAPIトークンやメンバーシップ周りだけなく、それ以外は共通

今回使用したトークンで使用した権限グループ一覧

{
    "result": [
        {
            "id": "eb56a6953c034b9d97dd838155666f06",
            "name": "Account API Tokens Read",
            "description": "Grants read access to account API Tokens",
            "scopes": [
                "com.cloudflare.api.account"
            ]
        },
        {
            "id": "5bc3f8b21c554832afc660159ab75fa4",
            "name": "Account API Tokens Write",
            "description": "Grants write access to account API Tokens",
            "scopes": [
                "com.cloudflare.api.account"
            ]
        },
        {
            "id": "6a018a9f2fc74eb6b293b0c548f38b39",
            "name": "Workers R2 Storage Bucket Item Read",
            "description": "Grants read access to Cloudflare R2 Bucket Scoped Storage",
            "scopes": [
                "com.cloudflare.edge.r2.bucket"
            ]
        },
        {
            "id": "2efd5506f9c8494dacb1fa10a3e7d5b6",
            "name": "Workers R2 Storage Bucket Item Write",
            "description": "Grants write access to Cloudflare R2 Bucket Scoped Storage",
            "scopes": [
                "com.cloudflare.edge.r2.bucket"
            ]
        },
        {
            "id": "b4992e1108244f5d8bfbd5744320c2e1",
            "name": "Workers R2 Storage Read",
            "description": "Grants read access to Cloudflare R2 Storage",
            "scopes": [
                "com.cloudflare.api.account"
            ]
        },
        {
            "id": "bf7481a1826f439697cb59a20b22293e",
            "name": "Workers R2 Storage Write",
            "description": "Grants write access to Cloudflare R2 Storage",
            "scopes": [
                "com.cloudflare.api.account"
            ]
        }
    ],
    "success": true,
    "errors": [],
    "messages": []
}

手順1では Account API Tokens Write をつけてPOSTしました。
手順2では Workers R2 Storage Read / Workers R2 Storage Write をつけてPOSTしました。

まとめ

今回、Cloudflare R2にアカウントAPIトークンを使って接続する方法を試してみました。
もし同じケースで困っている方がいましたらやってみてください。

25日になってないからセーフ…ですよね?

株式会社HIKKY

Discussion