mcpField
P
prowler-api

prowler-api

github.com/prowler-cloud開発15.1k73 回インストール今日更新
リポジトリ

prowler-api について

prowler-apiは、Prowlerのバックエンド開発者向けスキルです。テナント分離、RBAC、プロバイダーのライフサイクル、Celeryタスク、4データベース構成を扱い、安全な実装パターンを示します。

主な機能

  1. 01RLSによるテナント分離パターン
  2. 02RBACの権限チェック規則
  3. 03プロバイダーの検証とライフサイクル
  4. 04テナントコンテキスト付きCeleryタスク
  5. 054データベース構成のガイド

活用シーン

  1. 01テナント範囲のAPIクエリの実装
  2. 02ロールチェック付きバックエンド機能の構築
  3. 03安全な非同期タスクの作成
  4. 04処理に使うデータベースの選択

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/prowler-cloud/prowler --skill prowler-api

インストール後、Claude Code で/prowler-apiを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
security_patterns.py
celery_patterns.py
references/
modeling-decisions.md
configuration.md
file-locations.md
production-settings.md

詳細

使用する場面

Prowler 固有のパターンには、このスキルを使用します。

  • 行レベルセキュリティ(RLS)/テナント分離
  • RBAC 権限とロールチェック
  • プロバイダーのライフサイクルと検証
  • テナントコンテキストを使用する Celery タスク
  • マルチデータベースアーキテクチャ(4 データベース構成)

一般的な DRF パターン(ViewSets、Serializers、Filters、JSON:API)には、django-drf スキルを使用します。


重要なルール

  • ViewSet のコンテキスト外でクエリを実行する場合は、必ず rls_transaction(tenant_id) を使用します
  • 権限を確認する前に、必ず get_role() を使用します(最初のロールのみを返します)
  • デコレーターの順序は必ず @set_tenant、次に @handle_provider_deletion とします
  • M2M リレーションシップでは、必ず明示的な through モデルを使用します(RLS に必要です)
  • Celery タスクで、RLS コンテキストなしに Provider.objects にアクセスしてはいけません
  • 生 SQL や connection.cursor() を使用して、RLS を回避してはいけません
  • Django のデフォルト M2M を使用してはいけません。RLS では tenant_id を持つ through モデルが必要です

注:rls_transaction() は UUID オブジェクトと文字列の両方を受け付けます。内部で str(value) を使って変換します。


アーキテクチャの概要

4 データベースアーキテクチャ
データベースエイリアス用途RLS
defaultprowler_user標準 API クエリはい
adminadminマイグレーション、認証のバイパスいいえ
replicaprowler_user読み取り専用クエリはい
admin_replicaadmin管理者用読み取りレプリカいいえ
# When to use admin (bypasses RLS)
from api.db_router import MainRouter
User.objects.using(MainRouter.admin_db).get(id=user_id)  # Auth lookups

# Standard queries use default (RLS enforced)
Provider.objects.filter(connected=True)  # Requires rls_transaction context
RLS トランザクションのフロー
Request → Authentication → BaseRLSViewSet.initial()
                                    │
                                    ├─ Extract tenant_id from JWT
                                    ├─ SET api.tenant_id = 'uuid' (PostgreSQL)
                                    └─ All queries now tenant-scoped

実装チェックリスト

Prowler 固有の API 機能を実装する場合:

#パターン参照先要点
1RLS モデルapi/rls.pyRowLevelSecurityProtectedModel を継承し、制約を追加します
2RLS トランザクションapi/db_utils.pyrls_transaction(tenant_id) コンテキストマネージャーを使用します
3RBAC 権限api/rbac/permissions.pyget_role()、get_providers()、Permissions 列挙型
4プロバイダーの検証api/models.pyProvider モデルの validate_<provider>_uid() メソッド
5Celery タスクtasks/tasks.py、api/decorators.py、config/celery.pyタスク定義、デコレーター(@set_tenant、@handle_provider_deletion)、RLSTask 基底クラス
6RLS シリアライザーapi/v1/serializers.pyRLSSerializer を継承して tenant_id を自動挿入します
7Through モデルapi/models.pyすべての M2M で、tenant_id を持つ明示的な through モデルを使用する必要があります

ファイルの完全なパス:references/file-locations.md を参照してください


判断フロー

どの基底モデルを使うか?
Tenant-scoped data       → RowLevelSecurityProtectedModel
Global/shared data       → models.Model + BaseSecurityConstraint (rare)
Partitioned time-series  → PostgresPartitionedModel + RowLevelSecurityProtectedModel
Soft-deletable           → Add is_deleted + ActiveProviderManager
どのマネージャーを使うか?
Normal queries           → Model.objects (excludes deleted)
Include deleted records  → Model.all_objects
Celery task context      → Must use rls_transaction() first
どのデータベースを使うか?
Standard API queries     → default (automatic via ViewSet)
Read-only operations     → replica (automatic for GET in BaseRLSViewSet)
Auth/admin operations    → MainRouter.admin_db
Cross-tenant lookups     → MainRouter.admin_db (use sparingly!)
Celery タスクのデコレーターの順序は?
@shared_task(base=RLSTask, name="...", queue="...")
@set_tenant                    # First: sets tenant context
@handle_provider_deletion      # Second: handles deleted providers
def my_task(tenant_id, provider_id):
    pass

RLS モデルのパターン

from api.rls import RowLevelSecurityProtectedModel, RowLevelSecurityConstraint

class MyModel(RowLevelSecurityProtectedModel):
    # tenant FK inherited from parent
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(max_length=255)
    inserted_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)

    class Meta(RowLevelSecurityProtectedModel.Meta):
        db_table = "my_models"
        constraints = [
            RowLevelSecurityConstraint(
                field="tenant_id",
                name="rls_on_%(class)s",
                statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
            ),
        ]

    class JSONAPIMeta:
        resource_name = "my-models"
M2M リレーションシップ(必ず through モデルを使用)
class Resource(RowLevelSecurityProtectedModel):
    tags = models.ManyToManyField(
        ResourceTag,
        through="ResourceTagMapping",  # REQUIRED for RLS
    )

class ResourceTagMapping(RowLevelSecurityProtectedModel):
    # Through model MUST have tenant_id for RLS
    resource = models.ForeignKey(Resource, on_delete=models.CASCADE)
    tag = models.ForeignKey(ResourceTag, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            RowLevelSecurityConstraint(
                field="tenant_id",
                name="rls_on_%(class)s",
                statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
            ),
        ]

非同期タスクの応答パターン(202 Accepted)

実行時間の長い操作では、タスク参照とともに 202 を返します。

@action(detail=True, methods=["post"], url_name="connection")
def connection(self, request, pk=None):
    with transaction.atomic():
        task = check_provider_connection_task.delay(
            provider_id=pk, tenant_id=self.request.tenant_id
        )
    prowler_task = Task.objects.get(id=task.id)
    serializer = TaskSerializer(prowler_task)
    return Response(
        data=serializer.data,
        status=status.HTTP_202_ACCEPTED,
        headers={"Content-Location": reverse("task-detail", kwargs={"pk": prowler_task.id})}
    )

プロバイダー(11 種類をサポート)

プロバイダーUID の形式例
AWS12 桁123456789012
AzureUUID v4a1b2c3d4-e5f6-...
GCP6~30 文字、小文字、先頭は英字my-gcp-project
M365有効なドメインcontoso.onmicrosoft.com
Kubernetes2~251 文字arn:aws:eks:...
GitHub1~39 文字my-org
IaCGit URLhttps://github.com/user/repo.git
Oracle CloudOCID 形式ocid1.tenancy.oc1..
MongoDB Atlas24 文字の 16 進数507f1f77bcf86cd799439011
Alibaba Cloud16 桁1234567890123456

新しいプロバイダーの追加:ProviderChoices 列挙型に追加し、validate_<provider>_uid() 静的メソッドを作成します。


RBAC 権限

権限制御対象
MANAGE_USERSユーザーの CRUD、ロール割り当て
MANAGE_ACCOUNTテナント設定
MANAGE_BILLING請求/サブスクリプション
MANAGE_PROVIDERSプロバイダーの CRUD
MANAGE_INTEGRATIONSインテグレーション設定
MANAGE_SCANSスキャンの実行
UNLIMITED_VISIBILITYすべてのプロバイダーを表示(provider_groups をバイパス)
RBAC の可視性パターン
def get_queryset(self):
    user_role = get_role(self.request.user)
    if user_role.unlimited_visibility:
        return Model.objects.filter(tenant_id=self.request.tenant_id)
    else:
        # Filter by provider_groups assigned to role
        return Model.objects.filter(provider__in=get_providers(user_role))

Celery キュー

キュー用途
scansProwler のスキャン実行
overviewダッシュボードの集計(重大度、攻撃対象領域)
complianceコンプライアンスレポートの生成
integrations外部連携(Jira、S3、Security Hub)
deletionプロバイダー/テナントの削除(非同期)
backfill過去データのバックフィル処理
scan-reports出力の生成(CSV、JSON、HTML、PDF)

タスクの構成(Canvas)

複雑なワークフローには、Celery の Canvas プリミティブを使用します。

プリミティブ用途
chain()順次実行:A → B → C
group()並列実行:A、B、C を同時に実行
組み合わせ複雑なワークフロー向けに、ネストしたグループを含むチェーン

注: 結果の受け渡しを防ぐには .si()(シグネチャ不変)を使用します。結果を受け渡す必要がある場合は .s() を使用します。

例: チェーン、グループ、組み合わせのパターンについては、assets/celery_patterns.py を参照してください。


Beat スケジューリング(定期タスク)

操作要点
スケジュールを作成IntervalSchedule.objects.get_or_create(every=24, period=HOURS)
定期タスクを作成関数ではなくタスク名を使用し、kwargs=json.dumps(...) を指定します
スケジュール済みタスクを削除PeriodicTask.objects.filter(name=...).delete()
競合状態を回避DB のコミットを待つために countdown=5 を使用します

例: schedule_provider_scan パターンについては、assets/celery_patterns.py を参照してください。


高度なタスクパターン

@set_tenant の動作
モードkwargs 内の tenant_id関数に渡される tenant_id
@set_tenant(デフォルト)ポップ(削除)されますいいえ — 関数には渡されません
@set_tenant(keep_tenant=True)読み取られますが保持されますはい — 関数に渡されます
主なパターン
パターン説明
bind=Trueself.request.id、self.request.retries にアクセスします
get_task_logger(__name__)Celery タスクで適切なログを記録します
SoftTimeLimitExceeded強制終了の前に進捗を保存するために捕捉します
countdown=30実行を N 秒遅らせます
eta=datetime(...)指定した時刻に実行します

例: 高度なパターンについては、assets/celery_patterns.py を参照してください。


Celery の設定

設定値用途
BROKER_VISIBILITY_TIMEOUT86400(24h)長時間のタスクが再キューされるのを防ぎます
CELERY_RESULT_BACKENDdjango-db結果を PostgreSQL に保存します
CELERY_TASK_TRACK_STARTEDTrueタスクの開始時刻を追跡します
soft_time_limitタスクごとに設定SoftTimeLimitExceeded を発生させます
time_limitタスクごとに設定強制終了(SIGKILL)

設定全体: assets/celery_patterns.py および config/celery.py、config/settings/celery.py の実際のファイルを参照してください。


パーティション分割テーブル向けの UUIDv7

Finding と ResourceFindingMapping は、時刻ベースのパーティション分割に UUIDv7 を使用します。

from uuid6 import uuid7
from api.uuid_utils import uuid7_start, uuid7_end, datetime_to_uuid7

# Partition-aware filtering
start = uuid7_start(datetime_to_uuid7(date_from))
end = uuid7_end(datetime_to_uuid7(date_to), settings.FINDINGS_TABLE_PARTITION_MONTHS)
queryset.filter(id__gte=start, id__lt=end)

UUIDv7 を使う理由: 時系列順の UUID を使用すると、範囲クエリの際に PostgreSQL がパーティションをプルーニングできます。


RLS を使用した一括操作

from api.db_utils import batch_delete, create_objects_in_batches, update_objects_in_batches

# Delete in batches (RLS-aware)
batch_delete(tenant_id, queryset, batch_size=1000)

# Bulk create with RLS
create_objects_in_batches(tenant_id, Finding, objects, batch_size=500)

# Bulk update with RLS
update_objects_in_batches(tenant_id, Finding, objects, fields=["status"], batch_size=500)

セキュリティパターン

完全な例:assets/security_patterns.py を参照してください。

テナント分離の概要
パターンルール
ViewSet での RLSBaseRLSViewSet によって自動適用されます — tenant_id は JWT から取得します
Celery での RLS@set_tenant と rls_transaction(tenant_id) を必ず使用します
テナントをまたぐ検証多層防御:obj.tenant_id == request.tenant_id を確認します
ユーザー入力を決して信用しないJWT から取得した request.tenant_id を使用し、request.data.get("tenant_id") は決して使用しません
管理者 DB のバイパステナントをまたぐ管理者操作に限って使用します — すべてのテナントのデータが公開されます
Celery タスクのセキュリティ概要
パターンルール
名前付きタスクのみユーザー入力から動的にタスク名を指定しないでください
引数を検証するデータベースを検索する前に UUID の形式を確認してください
安全なキューイングコミット後にキューへ追加するため、transaction.on_commit() を使用してください
最新のリトライ方式autoretry_for、retry_backoff、retry_jitter を使用してください
時間制限タスクの停止を防ぐため、soft_time_limit と time_limit を設定してください
冪等性update_or_create または冪等性キーを使用してください
クイックリファレンス
# Safe task queuing - task only enqueued after transaction commits
with transaction.atomic():
    provider = Provider.objects.create(**data)
    transaction.on_commit(
        lambda: verify_provider_connection.delay(
            tenant_id=str(request.tenant_id),
            provider_id=str(provider.id)
        )
    )

# Modern retry pattern
@shared_task(
    base=RLSTask,
    bind=True,
    autoretry_for=(ConnectionError, TimeoutError, OperationalError),
    retry_backoff=True,
    retry_backoff_max=600,
    retry_jitter=True,
    max_retries=5,
    soft_time_limit=300,
    time_limit=360,
)
@set_tenant
def sync_provider_data(self, tenant_id, provider_id):
    with rls_transaction(tenant_id):
        # ... task logic
        pass

# Idempotent task - safe to retry
@shared_task(base=RLSTask, acks_late=True)
@set_tenant
def process_finding(tenant_id, finding_uid, data):
    with rls_transaction(tenant_id):
        Finding.objects.update_or_create(uid=finding_uid, defaults=data)

本番環境へのデプロイチェックリスト

すべての設定: references/production-settings.md を参照してください

本番環境へデプロイする前に、毎回実行してください。

cd api && uv run python src/backend/manage.py check --deploy
重要な設定
設定本番環境での値誤設定時のリスク
DEBUGFalseスタックトレース、設定、SQL クエリが漏えいします
SECRET_KEY環境変数、ローテーション済みセッションハイジャック、CSRF の回避
ALLOWED_HOSTS明示的なリストHost ヘッダー攻撃
SECURE_SSL_REDIRECTTrue認証情報が HTTP 経由で送信されます
SESSION_COOKIE_SECURETrueセッション Cookie が HTTP 経由で送信されます
CSRF_COOKIE_SECURETrueCSRF トークンが HTTP 経由で送信されます
SECURE_HSTS_SECONDS31536000(1 年)ダウングレード攻撃
CONN_MAX_AGE60 以上接続プールの枯渇

コマンド

# Development
cd api && uv run python src/backend/manage.py runserver
cd api && uv run python src/backend/manage.py shell

# Celery
cd api && uv run celery -A config.celery worker -l info -Q scans,overview
cd api && uv run celery -A config.celery beat -l info

# Testing
cd api && uv run pytest -x --tb=short

# Production checks
cd api && uv run python src/backend/manage.py check --deploy

リソース

ローカルリファレンス
関連スキル
  • 汎用 DRF パターン:django-drf スキルを使用してください
  • API テスト:prowler-test-api スキルを使用してください
Context7 MCP(推奨)

前提条件: 最新のドキュメントを検索できるよう、Context7 MCP サーバーをインストールしてください。

Prowler 固有のパターンを実装またはデバッグする際は、mcp_context7_query-docs を使って次のライブラリを検索してください。

ライブラリContext7 ID用途
Celery/websites/celeryq_dev_en_stableタスクのパターン、キュー、エラー処理
django-celery-beat/celery/django-celery-beat定期タスクのスケジューリング
Django/websites/djangoproject_en_5_2モデル、ORM、制約、インデックス

クエリの例:

mcp_context7_query-docs(libraryId="/websites/celeryq_dev_en_stable", query="shared_task decorator retry patterns")
mcp_context7_query-docs(libraryId="/celery/django-celery-beat", query="periodic task database scheduler")
mcp_context7_query-docs(libraryId="/websites/djangoproject_en_5_2", query="model constraints CheckConstraint UniqueConstraint")

注: 正しいライブラリ ID を探す必要がある場合は、最初に mcp_context7_resolve-library-id を使用してください。

コメント