mcpField
V
vtex-io-rbac

vtex-io-rbac

github.com/vtexセキュリティ47740 回インストール2 週間前に更新
リポジトリ

vtex-io-rbac について

VTEX IO アプリ開発者向けのアクセス制御スキルです。呼び出し元に応じたロールベースまたはリソースベースのポリシー選択を説明し、REST、GraphQL、VRN、認可設定、403 の調査を扱います。

主な機能

  1. 01ロールベースとリソースベースのポリシーの区別
  2. 02REST ルートのアクセス方針の設定
  3. 03GraphQL @auth ディレクティブによる認可
  4. 04リソースとプリンシパルを示す VRN の記述
  5. 05ポリシー設定に起因する 403 の調査

活用シーン

  1. 01REST エンドポイントを指定アプリに限定
  2. 02ユーザーや API キーに非公開ルートへのアクセスを許可
  3. 03GraphQL のクエリとミューテーションへの認可追加
  4. 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 と RESTREST のみ
呼び出し元がアクセス権を得る方法manifest.json で必要なポリシーを宣言する必要がありますポリシーの宣言は不要です。認証トークンを使って呼び出すだけです
設定場所アプリのルートにある policies.jsonservice.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 ディレクティブがありますか?
  • ワイルドカードを含むプリンシパルの範囲は、可能な限り限定されていますか?

関連スキル

参考資料

コメント