API 駆動に踏み込んだ瞬間に現れる壁
さくらのクラウドをコンソールから手で操作している限り、認証で困ることはほとんどない。ログインすれば、あとは画面が全部やってくれる。
ところが「インフラの払い出しからアプリケーションのデプロイまでを、すべてコードから API 経由で行う」という領域に踏み込むと、風景が一変する。さくらのクラウドには実質 2 つの系統——サービスプリンシパルと API キー——の認証情報があり、どちらがどの API に通るかが一様ではないからだ。しかも、通らなかったときに、どの認証情報のどの制約に引っかかったのかは、すぐには見分けにくい。結果として、本題であるはずのインフラ自動化に入る前に、認証の切り分けに時間を取られることになる。
EastCloud ではさくらのクラウド上でアプリケーション実行基盤(PaaS)を開発しており、コンテナのビルド、VPC・データベース・オブジェクトストレージの払い出し、コンテナ実行基盤へのデプロイまでを API から一気通貫で制御している。本稿は、その開発過程で実機検証を通じて確定させた「認証情報の地図」である。
以下に記す挙動は、すべて実際に API を叩いて確認したものである(主たる検証は 2026 年 5〜7 月、壁 4 は 2026 年 10 月に再確認)。さくらのクラウドは機能追加が活発なプラットフォームであり、ここに書かれた制約が後日解消されている可能性は十分にある。重要な判断を行う際は、公式ドキュメントと各自の環境で改めて確認されたい。
認証情報の 2 系統とその役割
細部に入る前に、まず全体像を示す。
| 認証情報 | 認証方式 | 主な用途 |
|---|---|---|
| サービスプリンシパル(SP) | 秘密鍵で署名した JWT からトークンを取得し、Bearer で送る | IAM 体系の API。プロジェクト配下のリソース操作 |
| リソース操作 API キー | Basic 認証(トークン + シークレット)。プロジェクトごとに作成し、アクセスレベルと対象サービスを設定する | 従来からの Cloud API 系(サーバ、ディスク、アプライアンス、コンテナレジストリ、オブジェクトストレージのコントロール面)、および Terraform・usacloud などのツール群 |
(コンソールの API キー作成画面で「リソース操作 API キー」を選び、アクセスレベルと対象サービスを設定すると、この 1 つの鍵でツールからもコントロール API からも使える。もう一方の「シングルサーバ API キー」は単一サーバの操作用で、本稿では扱わない。)

要約すれば、サービスプリンシパルは「機械のための身分証」であり、API キー系は「従来から実務を支えてきた鍵」である。さくらのクラウドは現在、新しい IAM の体系と、長年運用されてきた API 体系が並走しているフェーズにある。どちらか一方だけでは、すべての API に手が届かない。
「最も新しく、最も機械向けに設計されたサービスプリンシパルを使えば全部いけるはずだ」という発想は自然だが、実際には成立しない。以下、その理由を 4 つの具体的な壁として説明する。
壁 1:プロジェクトを作る権限は、どこに付けるのか
マルチテナントの基盤を設計するとき、「顧客が 1 社増えたら、その顧客専用のプロジェクトを自動作成し、その中にリソースを積む」という構成は素直な発想である。プロジェクトが課金と権限の境界になるので、分離の単位として理にかなっている。
ところが、サービスプリンシパルの認証情報でプロジェクト作成 API(POST /iam/1.0/projects)を呼ぶと 403 permission_denied が返ってきた。ロールの付与が足りないのだろうと考えて、オーナーを含む強い権限のロールを順に付与しても、結果は変わらなかった。
この壁の正体は、時期によって答えが変わる。 ここが本稿で最も注意を要する部分である。
2026 年 5 月時点:構造として不可能だった
当時、SP の認証情報で IAM のロール一覧を取得し、全件をダンプして確認したところ、用意されていたロール 26 件が、一件残らずプロジェクトスコープだった。プロジェクトより上位に効くロールが一覧に存在しない。さらに、最も強いはずのオーナーロールの説明文には、次のように明記されていた。
プロジェクトを管理する権限
プロジェクト作成以外のプロジェクトに関する全ての操作を行うことができる
つまりロールの付け方の問題ではなく、サービスプリンシパルにプロジェクト作成権限を与える手段が、構造として存在しなかった。プロジェクトを作成できるのはアカウントの所有者、すなわちコンソールを操作する人間だけ、という状態である。当時はこれを前提に、プロジェクトの払い出しを人間の運用手順として切り出す設計を採らざるを得なかった。
2026 年 7 月:組織・フォルダ階層の提供で状況が変わった
2026 年 7 月 9 日、さくらのクラウドは「組織・フォルダ IAM ポリシー」機能の提供を開始した(公式アナウンス)。アナウンスにはこうある。
これまで各プロジェクトごとに個別に設定していた IAM ポリシーが、組織またはフォルダ単位で一括付与できるようになります。設定した IAM ポリシーは階層構造に従って継承され、上位で付与した権限は下位のリソースにも適用されるようになります。
つまり 5 月に「不可能」だったのは当然だった。プロジェクトより上位の階層に IAM ポリシーを付与する仕組みそのものが、当時は存在しなかったのである。ロールが全部プロジェクトスコープだったのは、その帰結にすぎない。
本稿を書くにあたって同じロール一覧を取り直したところ、ロールは 31 件に増え、うち 4 件がプロジェクトスコープを超えていた。
| ロール | 付与可能な階層 | 説明 |
|---|---|---|
| フォルダ管理者 | フォルダ | フォルダに対する全ての操作を行うことができる |
| プロジェクト作成者 | フォルダ | プロジェクトを作成できる |
| サービスポリシー管理者 | 組織 | — |
| 管理者イベントログ | 組織 | — |
オーナーロールの説明からも「プロジェクト作成以外」という文言が消えている。
なお、公式アナウンスが述べているのは「組織・フォルダ単位での IAM ポリシー付与が可能になった」ことであり、個々のロール名には触れていない。上位階層に付与できるロールが一覧に現れるようになったのは本稿での観測であって、これらのロールが以前から定義だけ存在していたのか、今回追加されたのかまでは分からない。実務上重要なのは、いま組織階層でこれらを付与できるという事実のほうである。

そこで実際に権限を付与して検証したところ、サービスプリンシパルでプロジェクトを作成できた(201 Created)。手順は次のとおりである。
コンソールの IAM ポリシー画面を開き、スコープをプロジェクトから組織に切り替える。 ここが最大の落とし穴になる。プロジェクト作成者 は「フォルダ階層以上にのみ付与可能」なロールなので、プロジェクトを選択した状態の IAM ポリシー画面では、ロールの選択肢にすら現れない。実際、プロジェクトスコープでロールのプルダウンを開き IAM カテゴリを展開しても、出てくるのは「組織管理者」と「オーナー」の 2 つだけで、プロジェクト作成者 はどこにも無い。画面の右上にあるリソース階層のセレクタを、プロジェクトから組織(アカウント)に切り替える必要がある。
組織スコープで「アクセス権の付与」を行い、プリンシパルにサービスプリンシパル、ロールに プロジェクト作成者 を指定する。 なお、フォルダを 1 つも作っていなくても、組織階層で直接付与できる。
これだけで、それまで 403 だったプロジェクト作成 API が通るようになる。反映には最大 3 分かかるとコンソールには表示されるが、実際には保存直後の 1 回目で成功した。

この壁から得られる本当の教訓
「構造的に不可能」と結論した制約が、クラウド側の機能追加で解けることがある。
5 月の調査は、当時としては正確だった。ロール一覧を全件ダンプして確認しており、推測ではない。それでも 2 ヶ月後、機能がひとつ提供されたことで答えが変わった。しかも本稿の検証は、その提供開始からわずか 4 日後に行っている。あと数日ずれていたら、本稿は「不可能である」と書いて公開されていたはずだ。
クラウドの制約は動く標的である。半年前の検証結果を前提に設計を固定すると、すでに解けている制約を回避するための遠回りな仕組みを、いつまでも保守し続けることになる。 制約を前提に設計を歪めた箇所は、どこかに記録しておき、定期的に叩き直したほうがよい。あわせて、利用しているクラウドのリリースノートを継続的に追うこと。設計を縛っていた制約が、告知ひとつで消えていることがある。
補足:バリデーションは認可より先に走る
この検証中に、切り分けを誤らせる挙動に遭遇したので記しておく。
プロジェクト作成 API のリクエストで必須フィールド(code)を埋め忘れていた間、返ってくるのは一貫して 400 Invalid input だった。403 permission_denied は一度も見えない。リクエストの形が不正なうちは、バリデーションが先に走り、権限エラーが隠れる。
権限の有無を切り分けたいときは、まずリクエストボディを正しく埋めてから叩くこと。400 が返っている状態で「権限はあるらしい」と判断すると、事実と逆の結論に至る。
壁 2:SP の「リソース ID」と「キー ID」は別物である
サービスプリンシパルは 2 階層の構造を持つ。
サービスプリンシパル(本体 = 身分そのもの)
├─ リソース ID:12 桁の数値
└─ サービスプリンシパルキー(公開鍵の登録。複数持てる)
├─ キー ID:UUID 形式(36 文字)
└─ KID:公開鍵から計算されるフィンガープリント(43 文字)
JWT を組み立てる際、iss および sub クレームに入れるのは 本体のリソース ID(12 桁の数値) である。キーの UUID ではない。またヘッダの kid に入れるのは、キー ID の UUID ではなく KID のほうである。

ここで SP キーの UUID を SP の ID だと取り違えて設定すると、次のエラーが返る。
JWTの検証に失敗しました
このエラーで引っかかりやすいのは、つい鍵そのものを疑ってしまう点にある。秘密鍵も公開鍵も KID もすべて正しく、署名の計算にも誤りがない。それでも「検証に失敗しました」と出ると、鍵の生成方法や署名アルゴリズムのほうを疑いたくなる。だが実際には鍵は完全に正しく、「誰として名乗るか」の欄だけが間違っている。
似た形式の識別子が同じ画面に 3 つ並んでいれば、取り違えは起きやすい。コンソールで SP の詳細画面を開き、「リソース ID」と明記された 12 桁の数値を使う。 本稿でこの一点だけでも持ち帰る価値がある。
さらに静かな罠:取り違えても、エラーでは気づけない
これに関連して、より発見しにくい問題がある。
認証情報を手で設定するとき、どの SP のものかを取り違えても、各値が整合してさえいれば、認証も API 呼び出しもそのまま通ってしまう。 検証中、口頭で受け取った番号をそのまま設定したところ、問題なく通ったので正しいものと思い込んでいた。だが後で確かめると、意図していたのとは別の SP を使っていた。間違いは、エラーとしては一度も表に出てこなかった。
「認証が通った」は「意図した SP で認証が通った」を意味しない。SP の ID は、必ずコンソールの詳細画面(プロジェクト名も併記される)で裏を取る必要がある。
壁 3:同じ取り違えが、IaaS では通り、オブジェクトストレージでは弾かれる
壁 2 で、JWT のヘッダ kid に入れるのは KID(フィンガープリント)であって、キー ID の UUID ではない、と書いた。この取り違えが、厄介な形で表に出ることがある。
Terraform や usacloud のプロファイルにサービスプリンシパルの情報を設定して、kid に相当する欄へ誤って UUID を入れてしまったとする。すると、こうなった(2026 年 6 月の検証)。
- サーバやゾーンの一覧取得(IaaS 系)→ 通ってしまう
- オブジェクトストレージのコントロール API →
API Error 400: JWTの検証に失敗しました
同じ一つの誤り(kid の取り違え)なのに、IaaS 系は寛容に受け入れ、オブジェクトストレージのコントロール API だけが厳密に弾く。だから誤りが片方でしか表に出ず、原因の切り分けが難しくなる。 kid を正しく KID にすれば、どちらも通る。
この非対称を踏まないための運用上の対処はこうだ。
Terraform や usacloud のプロファイルには、「リソース操作 API キー」(トークンとシークレットの組)を入れる。 API キーは Basic 認証で、kid のような取り違えどころが無い。SP で組むより、この分岐を踏みにくい。
API キーは、権限の範囲を明示して発行する。 アクセスレベルを「作成・削除」にし、対象サービスにオブジェクトストレージやコンテナレジストリを含める。
インフラ構築ツールが使う認証情報と、アプリケーションのランタイムが使う認証情報を、明確に別物として扱う。 両者は役割も生存期間も異なる。ランタイム側はサービスプリンシパルで問題なく動作する。
「どちらか一方の認証方式に統一しよう」という発想は自然だが、少なくとも現時点では、用途ごとに適した認証情報を選ぶほうが素直に動く。統一を試みて半日を溶かすより、地図を持っておくほうが速い。
壁 4:一覧 API は、使った鍵のプロジェクトしか返さない
最後に、認証そのものというより「認証の見え方」に関する問題を挙げる。
IaaS API でリソースの一覧を取ると、返ってくるのは、使った認証情報が属するプロジェクトのリソースだけである。別のプロジェクトに紐づく鍵で同じゾーンを引けば、まったく別の一覧が返り、両者は 1 件も重ならない。アカウントにいくつプロジェクトがあっても、一覧 API が一度に見せるのは、そのとき使った鍵の 1 プロジェクト分だ。
これは便利なようで、棚卸しのときに足をすくう。ひとつの鍵で全ゾーンを舐めても、それは 1 プロジェクトを数えただけで、別のプロジェクトに建てたリソースは、丸ごと視界から消える。顧客ごとにプロジェクトを分けていれば、その鍵でなければ見えない。
とくに「残っているものは無いか」「課金はこれで全部か」を語るときに危ない。「これで全部だ」と断じる前に、どの鍵で見たのかを添える。 アカウント全体を数えたいなら、関係する鍵をすべて列挙し、鍵ごとに一覧を引く。そして最終的な正本は、コンソールの「契約リソース」画面に置く(ただしこのパネルは課金ベースの集計で、数値の反映に 1 日ほどの遅れが出る)。
一覧 API は便利だが、それが答えている質問は、こちらが聞きたい質問とは違うかもしれない。 「アカウントに何があるか」を聞いたつもりで、API は「この鍵のプロジェクトに何があるか」を答えている。これはさくらのクラウドに限らず、クラウド API 全般に通じる教訓である。
地図を持って歩く
改めて整理する。
サービスプリンシパルは、プロジェクト内のリソースを機械が操作するための身分証である。 プロジェクトそのものを作成させたい場合は、組織階層で プロジェクト作成者 ロールを付与する(プロジェクトスコープの画面では選択肢に出ない)。JWT に入れるのは本体の 12 桁のリソース ID であり、キーの UUID ではない。
リソース操作 API キーは、従来からの Cloud API 系を叩くための鍵である。 サーバ、ディスク、アプライアンス、コンテナレジストリ、オブジェクトストレージのコントロール面はこの系統に乗っており、Terraform や usacloud もこれを使う。プロジェクトごとに作成し、アクセスレベルと対象サービスを設定する。kid のような取り違えどころが無いので、ツールのプロファイルにはこちらが向く。
そして、一覧 API は、使った鍵のプロジェクトしか返さない。
これらを事前に知っていれば、認証で止まることはなくなる。さくらのクラウドは、新しい IAM の体系と、実績のある既存の API 体系が並走する過渡期にある。本稿で挙げた 4 つの壁は、いずれもその「継ぎ目」に集中している。裏を返せば、継ぎ目の位置さえ把握していれば、あとは素直に自動化できるということでもある。
なお、API の wire 仕様(リクエストやレスポンスの実際の形)を確認する必要が生じた場合、公式の OpenAPI 定義に加えて、Terraform プロバイダが内部的に利用している Go ライブラリのソースが有力な一次資料になる。特に従来からの Cloud API 系は OpenAPI として公開されていない部分があり、「OpenAPI に定義がない」ことは「API が存在しない」ことを意味しない。この点も、実装前に知っておく価値がある。
なお、本稿で触れた「認証が通ったことと、意図どおり通ったことは別である」という話は、認証に限った問題ではない。続編として、処理が成功を返しながら実際には動いていない「サイレント障害」とどう向き合うかを別稿で扱った。
追記(2026 年 10 月 3 日): 公開後の再点検で、いくつかの誤りを見つけ、実機で確かめたうえで訂正した。主なものは 2 点。壁 4「一覧 API の返す範囲」が実機と逆だったこと(再測定して修正)。そして当初「認証情報 3 種」としていたが、実際には「リソース操作 API キー」が 1 種類で、SP と API キーの 2 系統だったこと(タイトル・冒頭の表・壁 3 の枠組みを見直した)。仕様も実機も、そして過去の自分の観測も、時間とともにずれていく——というのは、この連載自身のテーマでもある。訂正を隠さず残しておく。
参考リンク
- さくらのクラウド「組織・フォルダIAMポリシー」機能 提供開始のお知らせ(2026年7月9日) — 本稿の壁1が解消された根拠
- サービスプリンシパル | さくらのクラウド マニュアル — JWT のヘッダ・ペイロードに何を入れるかが記載されている
- IAMポリシー | さくらのクラウド マニュアル — ロール一覧と付与可能な階層
- さくらのクラウド マニュアル
- sacloud/iaas-api-go — 従来からの Cloud API の wire 仕様を確認する際の一次資料
- sacloud/sacloud-sdk-go — 個別 SDK の統合先
- sacloud/usacloud — CLI
- sacloud/terraform-provider-sakuracloud
