Fastly Compute のサービスを publish したあと、KV Store を使おうとして fastly kv-store list を実行したところ、403 Forbidden を返し続ける状態になりました。Pay-as-you-go プランへの切り替えと API トークンの再発行を済ませても解消せず、切り分けに 30 分ほどかかりました。
最初は気づきにくい論点がいくつかあったため、同じ状況に当たった人が即座に解決できるよう、チェックリストとしてまとめます。
検証環境: Fastly CLI v14.3.1(Viceroy 0.17.0)、Compute サービス、macOS 14。
TL;DR
-
Fastly Key Value Store は Pay-as-you-go プランに含まれていない別売プロダクトです。
Account → Products → Key Value Storeから別途有効化する必要があります (もっとも見落としやすい点) - Free tier ありはStorage 1 GB/月、Class A Operations 100,000 ops/月。月額最低料金なし
- Personal Tokens 一覧に表示される文字列は Token "ID" であって、API に渡す Token 値ではありません
- direnv の
FASTLY_API_TOKENはfastly auth loginで更新した profile よりも優先されます
観測される挙動
$ fastly kv-store list
ERROR: the Fastly API returned 403 Forbidden: Forbidden (forbidden).
This error may indicate insufficient token permissions, an incorrect account context, or restricted access to the requested resource.
API を直接叩いても同じ結果になります。
$ curl -s -H "Fastly-Key: $FASTLY_API_TOKEN" -w "\n%{http_code}\n" \
https://api.fastly.com/resources/stores/kv
{"title":"Forbidden","status":403,"detail":"forbidden"}
403
エラーメッセージから「token の Scope が足りない」と読み取れますが、Scope が十分であっても 403 になるケースがあります。
同じトークンでの Secret Store との比較
最初にやるべきは、同じトークンで Secret Store API を叩いてみることです。Secret Store も Compute 系のリソースで、エンドポイント形式は KV Store とほぼ同一です。
$ curl -s -H "Fastly-Key: $FASTLY_API_TOKEN" -w "\n%{http_code}\n" \
https://api.fastly.com/resources/stores/secret
{"data":[],"meta":{...}}
200
$ curl -s -H "Fastly-Key: $FASTLY_API_TOKEN" -w "\n%{http_code}\n" \
https://api.fastly.com/resources/stores/kv
{"title":"Forbidden","status":403,"detail":"forbidden"}
403
| エンドポイント | 結果 |
|---|---|
/resources/stores/secret |
200 |
/resources/stores/kv |
403 |
Secret Store が 200 を返すのに KV だけ 403 になるなら、Token の Scope 不足より先に、KV Store 機能がアカウントで有効化されているかを疑います。同じ「Compute 系の Resource Store」エンドポイントなので、片方だけ拒否されるのは不自然に見えます。しかし Fastly では Secret Store と KV Store の課金体系が分かれており、別個に有効化する必要があります。
チェックすべき 3 ポイント
1. Pay-as-you-go プランに KV Store は含まれていない
Fastly の Compute は Pay-as-you-go プランで利用できますが、Key Value Store は同プランに含まれていません。manage.fastly.com → Account → Products → Key Value Store を開くと、専用のプロダクトページがあります。
未有効化の状態だと、ページに Free tier のバッジと Purchase KV Stores ボタンが表示され、これを押すまで API 側は 403 を返し続けます。
Purchase というラベルになっていますが、Free tier 内であれば実費は発生しません。
Free tier の枠
| 項目 | 無料枠 | 超過分 |
|---|---|---|
| Storage | 1 GB / 月 | $0.50 / GB / 月 |
| Class A Operations(write 系) | 100,000 ops / 月 | 公式単価参照 |
| Class B Operations(read 系) | 1,000,000 ops / 月 | 公式単価参照 |
| 月額最低料金 | なし | — |
Compute から KV を読み書きする一般的な開発検証規模(数百キー、数 KB/key、月数千 ops)では、すべて無料枠内に収まります。
2. Personal Tokens 一覧の文字列は Token "ID" であって Token 値ではない
ここが二重に紛らわしいポイントです。manage.fastly.com/account/personal/tokens のリスト画面に表示される短い文字列(16 文字程度)は Token ID で、参照用の識別子です。
API に渡すべき Token 値(30〜40 文字) は、生成直後の画面でのみ表示されます。
| 表示場所 | 名前 | 用途 | 長さ |
|---|---|---|---|
| 一覧画面 | Token ID | 内部参照用の識別子 | 16 文字 |
| 生成直後の "Created" 画面 | API Token | API 認証に使う値 | 30〜40 文字 |
Token ID を .env や fastly auth login に貼り付けると、403 ではなく 401 Unauthorized が返ります。
$ fastly auth login
Paste your API token: <Token ID をペースト>
ERROR: the Fastly API returned 401 Unauthorized: Provided credentials are missing or invalid.
Token 値は再表示できないため、生成画面でコピーし損ねた場合は、その Token を Revoke して再発行する必要があります。
3. direnv の FASTLY_API_TOKEN が profile より優先される
Fastly CLI のトークン優先順位は、ヘルプの記述とエラーメッセージの両方に明示されています。
Token precedence: --token (raw or stored name) > FASTLY_API_TOKEN > fastly.toml profile > default auth token.
.envrc や .env.local を direnv 経由で読ませ、FASTLY_API_TOKEN を export している環境を考えます。この場合、fastly auth login で profile を更新しても 環境変数の token が優先されます。Profile 側だけ更新して env を放置すると、いつまで経っても古いトークンで API を叩き続けることになります。
# 1. .env.local の FASTLY_API_TOKEN を新しい token 値に書き換える
# 2. direnv に再読込させる
direnv reload
# 3. 反映を確認
echo "${FASTLY_API_TOKEN: -4}" # 新しい token の末尾 4 文字が出れば OK
# 4. profile も同じ値で更新(任意だが揃えておくと安全)
fastly auth login
env と profile を混在させて運用していると後から犯人探しが大変になるため、どちらか片方に寄せるのを推奨します。
開通後の手順
KV Stores が有効化され、fastly kv-store list が空応答(200)を返すようになれば、あとは通常のフローです。順に Store を作成・テスト・サービスにリンクします。
# 1. KV Store を作成
$ fastly kv-store create --name=siteforce-corrections-dev
SUCCESS: Created KV Store 'siteforce-corrections-dev' (***)
# 2. テスト書き込み・読み取り
$ fastly kv-store-entry create --store-id=*** --key=test --value=test-value
SUCCESS: Created key 'test' in KV Store '***'
$ fastly kv-store-entry describe --store-id=*** --key=test
Key: test
Generation: ***
Metadata:
# 3. Compute Service にリンク(active version を autoclone)
$ fastly resource-link create \
--service-id=*** \
--resource-id=*** \
--name=CORRECTIONS \
--autoclone --version=active
SUCCESS: Created service resource link "CORRECTIONS" (***) on service *** version 3
# 4. 新 version を activate
$ fastly service-version activate --service-id=*** --version=3
SUCCESS: Activated service *** version 3
--name=CORRECTIONS の部分は、Compute コードから new KVStore("CORRECTIONS") でアクセスする際のバインディング名と一致させてください。fastly.toml の [setup.kv_stores.CORRECTIONS] ブロックや [local_server.kv_stores.CORRECTIONS] の名前と揃えるのが定石です。
# fastly.toml
[local_server]
[local_server.kv_stores]
[local_server.kv_stores.CORRECTIONS]
file = "fixtures/corrections.json"
format = "json"
[setup]
[setup.kv_stores]
[setup.kv_stores.CORRECTIONS]
description = "Per-URL HTML injection rules used by the Compute service"
切り分けフロー
fastly kv-store list が 403 を返したときの切り分け順序を図にまとめます。
まとめ
要点は次の 3 点です。
- KV Stores は別売プロダクトです。Pay-as-you-go プラン契約だけでは使えません
- Free tier があるため、開発検証段階での実費は通常 $0 です
- Token 周りは「一覧画面の文字列は ID であって値ではない」「direnv の env が profile より強い」を覚えておけば 401 / 認証エラーで詰まりません
この 3 点さえ押さえれば、403 で消える時間は最小限に抑えられます。