vtex-io-rbac について
VTEX IO アプリ開発者向けのアクセス制御スキルです。呼び出し元に応じたロールベースまたはリソースベースのポリシー選択を説明し、REST、GraphQL、VRN、認可設定、403 の調査を扱います。
主な機能
- 01ロールベースとリソースベースのポリシーの区別
- 02REST ルートのアクセス方針の設定
- 03GraphQL @auth ディレクティブによる認可
- 04リソースとプリンシパルを示す VRN の記述
- 05ポリシー設定に起因する 403 の調査
活用シーン
- 01REST エンドポイントを指定アプリに限定
- 02ユーザーや API キーに非公開ルートへのアクセスを許可
- 03GraphQL のクエリとミューテーションへの認可追加
- 04ワイルドカードポリシーによるアクセス拒否の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill vtex-io-rbacインストール後、Claude Code で/vtex-io-rbacを入力して読み込まれたか確認します。
詳細
VTEX IO アクセス制御(RBAC)
このスキルを使用する場面
VTEX IO アプリのルートやリソースへのアクセスを制御する必要がある場合に、このスキルを使用します。
- ロールベース(
policies.json)とリソースベース(service.jsonのポリシー)のアクセス制御を選択する - 特定のアプリ、ユーザー、API キーのみが呼び出せるようにREST エンドポイントを保護する
@authディレクティブを使用してGraphQL の認可を設定する- プリンシパルを宣言するための VRN(VTEX Resource Name)構文を理解する
- ポリシーの不足や設定ミスが原因の 403 Forbidden エラーをデバッグする
以下の用途では、このスキルを使用しないでください。
- 一般的なサービスアーキテクチャ(
vtex-io-service-appsを使用してください) - PCI コンプライアンスと決済セキュリティ(
payment-pci-securityを使用してください) - ルートのプレフィックスと CDN の動作(
vtex-io-service-paths-and-cdnを使用してください)
判断ルール
ロールベースとリソースベースのポリシー
ロールベース(policies.json) | リソースベース(service.json のポリシー) | |
|---|---|---|
| 呼び出せる対象 | 他の IO アプリのみ(単独、または他のアプリに代わって) | アプリ、ユーザー、インテグレーション(API キー) |
| API の種類 | GraphQL と REST | REST のみ |
| 呼び出し元がアクセス権を得る方法 | manifest.json で必要なポリシーを宣言する必要があります | ポリシーの宣言は不要です。認証トークンを使って呼び出すだけです |
| 設定場所 | アプリのルートにある policies.json | service.json のルート定義内にある policies 配列 |
| 使用する場面 | GraphQL エンドポイントの公開、またはアプリ間のみで使用する REST エンドポイントの公開 | REST エンドポイントへのユーザー、API キー、または特定のアプリのアクセス制御 |
適切な方法の選択
- GraphQL エンドポイント → ロールベースのポリシー(
policies.json)および/または、ユーザーレベルの認可のためにスキーマで@authディレクティブを使用します。 - 他の IO アプリのみが呼び出す REST エンドポイント → ロールベースのポリシー(
policies.json)を使用します。利用側のアプリはmanifest.jsonでポリシーを宣言する必要があります。 - ユーザーまたは API キーが呼び出す REST エンドポイント →
service.jsonのリソースベースのポリシーを使用します。ルートを"public": falseに設定し、プリンシパルを定義します。 - パブリック REST エンドポイント(認証なし) →
service.jsonで"public": trueに設定します。ポリシーは不要ですが、誰でも呼び出せることに注意してください。
VRN 構文
VRN(VTEX Resource Name)は、リソースとプリンシパルを識別します。
vrn:{service}:{region}:{account}:{workspace}:{path}
- アプリ:
vrn:apps:*:*:*:app/{vendor}.{app-name}@{version} - ユーザー:
vrn:vtex.vtex-id:*:*:*:user/{email} - API キー:
vrn:vtex.vtex-id:*:*:*:user/vtexappkey-{account}-{hash} - ワイルドカード:
*はセグメント内の任意の値に一致します。app/*はすべてのアプリに一致します。user/*@gmail.comはすべての Gmail ユーザーに一致します。
厳格な制約
制約:ユーザーまたは API キーがアクセスする必要がある場合は、リソースベースのポリシーを使用する
ロールベースのポリシーが機能するのは、アプリ間の通信のみです。ユーザー(管理者またはストアフロント)やインテグレーション(API キー)がエンドポイントを呼び出す必要がある場合は、service.json でルートを "public": false に設定し、リソースベースのポリシーを必ず使用してください。
重要な理由 — ユーザーまたは API キーが呼び出すルートにロールベースのポリシーを設定すると、これらの呼び出し元には 403 Forbidden が返されます。ロールベースのポリシーはユーザーやインテグレーションのトークンを評価しないためです。
検出方法 — 管理者ユーザーや外部インテグレーションから呼び出せる必要があるプライベートルートに、policies.json の設定しかなく、service.json に policies 配列がない。
正しい例 — ユーザー/インテグレーションからのアクセスには、service.json でリソースベースのポリシーを使用します。
{
"routes": {
"orders": {
"path": "/_v/private/my-app/orders",
"public": false,
"policies": [
{
"effect": "allow",
"actions": ["GET", "POST"],
"principals": [
"vrn:vtex.vtex-id:*:*:*:user/*@mycompany.com",
"vrn:apps:*:*:*:app/partner.integration-app@*"
]
}
]
}
}
}
誤った例 — ユーザーが必要とするルートに policies.json しか設定していません。
// policies.json — this only covers app-to-app, not users
[
{
"name": "access-orders",
"statements": [
{
"effect": "allow",
"actions": ["GET"],
"resources": ["vrn:my-app:*:*:*:/_v/private/my-app/orders"]
}
]
}
]
// Users calling this route still get 403
制約:拒否ポリシーは許可ポリシーより優先される
リソースベースのポリシーで allow ルールと deny ルールのプリンシパルが重複する場合、常に拒否が優先されます。許可ルールのワイルドカードが、特定の拒否ルールと重複しないよう注意してください。
重要な理由 — app/* に対する広範な allow と、app/vendor.bad-app@* に対する特定の deny を組み合わせると、bad-app は正しくブロックされます。一方、広範な deny と特定の allow を組み合わせると、許可するつもりのものも含めてすべてブロックされます。
検出方法 — 同じルートに、効果が競合しプリンシパルが重複するポリシーエントリが複数ある。
正しい例 — 広く許可し、特定の対象を拒否します。
{
"policies": [
{
"effect": "allow",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/*"]
},
{
"effect": "deny",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/untrusted.app@*"]
}
]
}
誤った例 — 広く拒否し、特定の対象を許可しようとしています(許可は上書きされます)。
{
"policies": [
{
"effect": "deny",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/*"]
},
{
"effect": "allow",
"actions": ["POST"],
"principals": ["vrn:apps:*:*:*:app/trusted.app@*"]
}
]
}
推奨パターン
ロールベースのポリシー(policies.json)
[
{
"name": "resolve-graphql",
"description": "Allows apps to resolve GraphQL requests",
"statements": [
{
"effect": "allow",
"actions": ["POST"],
"resources": [
"vrn:vtex.store-graphql:{{region}}:{{account}}:{{workspace}}:/_v/graphql"
]
}
]
}
]
呼び出し元のアプリは、manifest.json でポリシーを宣言します。
{
"policies": [
{
"name": "resolve-graphql"
}
]
}
混合アクセス用のリソースベースのポリシー
{
"routes": {
"webhook": {
"path": "/_v/private/my-app/webhook",
"public": false,
"policies": [
{
"effect": "allow",
"actions": ["POST"],
"principals": [
"vrn:apps:*:*:*:app/vtex.orders-broadcast@*",
"vrn:vtex.vtex-id:*:*:*:user/vtexappkey-myaccount-*"
]
}
]
}
}
}
GraphQL の @auth ディレクティブ
GraphQL エンドポイントでは、ユーザーレベルの認可に @auth ディレクティブを使用します。
type Query {
orders: [Order] @auth(productCode: "10", resourceCode: "list-orders")
adminSettings: Settings
@auth(productCode: "10", resourceCode: "admin-settings")
}
type Mutation {
updateSettings(input: SettingsInput!): Settings
@auth(productCode: "10", resourceCode: "admin-settings")
}
@auth ディレクティブは、指定された productCode と resourceCode に対する呼び出し元の License Manager ロールを確認します。
よくある失敗パターン
- ロールベースのルートでユーザーに 403 が返される — ルートに
policies.jsonしか設定されていません。ロールベースのポリシーはユーザーや API キーには適用されないため、403 が返されます。 public: trueの範囲が広すぎる — プライベートにすべきルートがパブリックに設定されています。認証なしで誰でも呼び出せます。- 呼び出し元のマニフェストにポリシーがない — アプリがロールベースで保護されたルートを呼び出そうとしていますが、
manifest.jsonでポリシーを宣言していません。その結果、403 が返されます。 - VRN の誤記 — VRN 内のベンダー名、アプリ名、またはプリンシパルの形式が間違っています。一致しないまま失敗し、403 が返されます。
- 拒否ルール内のワイルドカード —
app/*を使った広範な拒否ルールは、信頼できるアプリを含むすべてのアプリをブロックします。拒否が優先されます。 - GraphQL のミューテーションに
@authがない — データを変更するミューテーションにロールチェックがなくてもアクセスできます。
レビュー用チェックリスト
- 呼び出し元(アプリかユーザー/インテグレーションか)に応じて、アクセス制御の種類(ロールベースかリソースベースか)は適切ですか?
- プライベートルートは
"public": falseに設定され、適切なポリシーが指定されていますか? - プリンシパルの種類(アプリ、ユーザー、API キー)に応じて、VRN は正しい形式になっていますか?
- 呼び出し元のアプリは、必要なロールベースのポリシーを
manifest.jsonで宣言していますか? - 拒否ルールは慎重に使用されていますか(プリンシパルが重複する場合、許可ルールより優先されます)?
- GraphQL のミューテーションに、正しい
productCodeとresourceCodeを指定した@authディレクティブがありますか? - ワイルドカードを含むプリンシパルの範囲は、可能な限り限定されていますか?
関連スキル
- vtex-io-service-apps — サービスクラス、クライアント、ルート設定
- vtex-io-app-contract — マニフェスト、ビルダー、ポリシー宣言
- vtex-io-graphql-api — GraphQL スキーマと
@authディレクティブの詳細 - vtex-io-service-paths-and-cdn — ルートプレフィックスのパターン
参考資料
- アプリのリソースへのアクセス制御 — ロールベースおよびリソースベースのポリシー、VRN の構文、プリンシパルの種類
- 認証トークンを使用したアプリの認証 — アプリ間およびユーザーからアプリへの通信に使用する認証トークンの種類
- IO アプリにおける GraphQL の認可 —
@authディレクティブの使用方法 - VTEX IO VRN — VTEX Resource Name の形式と例