【技術解説】Supabase×Vercelのセキュリティ監視を自動化 - Claude Codeで半日構築
![]()
この記事で解決できること
- Supabaseのセキュリティ警告を見逃さなくなる(メール確認不要)
- Vercelのデプロイ失敗を即座に把握できる
- セキュリティ問題の修正方法がわかる(RLS、search_path等)
- Claude Codeで監視システムを構築する具体的な方法がわかる
「Supabaseからセキュリティアラートのメールが来てるけど、毎回確認するのが面倒...」という方は、この記事を読めば半日で自動通知システムが作れます。
きっかけ:ある朝届いた5件のERROR
ある朝、Supabaseから5件のERRORを含むセキュリティアラートメールが届きました。
内容を確認すると:
auth_users_exposed- auth.usersが公開されているビューsecurity_definer_view- SECURITY DEFINER付きの危険なビューrls_disabled_in_public- RLS未設定のテーブル
正直、「え、これヤバいやつじゃん」と焦りました。
でも同時に思ったのが「これ、毎回メールで確認するの面倒だな...」ということ。メールは埋もれるし、気づいたときには数日経ってることもある。
そこでClaude Codeに相談してみました。
Claude Codeへの最初の相談
実際に送ったプロンプト
Supabaseから毎日セキュリティアラートのメールが来るんだけど、
これを毎朝Slackに通知するシステムを作りたい。
要件:
- Supabaseの全プロジェクトをスキャン
- ERROR/WARNの数をサマリーで通知
- 修正方法も一緒に教えてほしい
- 毎朝7:30に自動実行
可能?
Claude Codeの回答(要約)
可能です。以下の構成で実装できます:
1. Supabase Management API の /advisors/security エンドポイントで
セキュリティ警告を取得
2. Slack Incoming Webhook で通知
3. GitHub Actions で毎朝定期実行
まず、Supabase APIの仕様を調べてきますね。
この時点で「APIあるんだ」と知りました。自分で調べてたら1日かかってたと思います。
構築中に遭遇した3つの問題と解決策
問題1:Supabase Access Tokenの権限不足
症状:APIを叩くと 403 Forbidden が返ってくる
Claude Codeとのやり取り:
私:「403エラーが出る」
Claude:「Access Tokenの権限を確認してください。
Dashboard → Account → Access Tokens で、
以下のスコープが必要です:
- projects:read
- database:read
新しいトークンを発行してみてください」
私:「新しいトークン作った」
Claude:「.envファイルを更新して、再度実行してみてください」
解決策:新しいAccess Tokenを発行し直したら解決。古いトークンは権限が足りなかった。
問題2:GitHub Actionsのcron設定ミス
症状:朝7:30に実行したいのに、夜中に実行される
原因:cronはUTC基準だと知らなかった
# 間違い(UTC 7:30 = JST 16:30)
- cron: '30 7 * * *'
# 正解(UTC 22:30 = JST 7:30)
- cron: '30 22 * * *'
Claude Codeが「cronはUTCですよ」と教えてくれて、すぐ修正できました。
問題3:Slack通知が長すぎて見づらい
症状:全プロジェクトの全警告を列挙したら、通知が100行超えて読めない
Claude Codeへの相談:
私:「通知が長すぎる。もっとコンパクトにしたい」
Claude:「以下のように改善しましょう:
1. プロジェクトごとにERROR/WARNの件数だけサマリー表示
2. 詳細は『修正プロンプト』としてコードブロックに格納
3. 問題がなければ通知しない(サイレント成功)」
この提案で、通知が10行程度に収まるようになりました。
使用するAPI・機能の技術解説
このシステムで使用している3つの主要なAPIについて、それぞれの機能と取得できるデータを解説します。
Supabase Security Advisors API
Supabaseには、プロジェクトのセキュリティ状態を監査するSecurity Advisors APIがあります。
このAPIは、Supabase Management APIの一部として提供されており、以下のエンドポイントでアクセスできます:
GET https://api.supabase.com/v1/projects/{project_id}/advisors/security
取得できるセキュリティ情報
| 検査項目 | 説明 | 重要度 |
|---|---|---|
auth_users_exposed |
auth.usersテーブルが公開ビューから参照されていないか | ERROR |
rls_disabled_in_public |
publicスキーマのテーブルにRLSが設定されているか | ERROR |
security_definer_view |
SECURITY DEFINERが設定された危険なビューがないか | ERROR |
function_search_path_mutable |
関数のsearch_pathが固定されているか | WARN |
auth_rls_initplan |
RLSポリシーでauth関数が効率的に呼ばれているか | WARN |
no_primary_key |
テーブルにプライマリキーが設定されているか | INFO |
レスポンス例
{
"result": [
{
"name": "rls_disabled_in_public",
"title": "RLS Disabled in Public",
"level": "ERROR",
"categories": ["SECURITY"],
"description": "Tables in 'public' schema with RLS disabled",
"metadata": {
"tables": ["user_data", "temp_logs"]
}
}
]
}
このAPIのおかげで、Supabase Dashboardにログインしなくてもセキュリティ状態を自動チェックできます。
Supabase Projects API
Security Advisors APIを使う前に、まず監視対象のプロジェクト一覧を取得する必要があります:
GET https://api.supabase.com/v1/projects
取得できるプロジェクト情報
{
"id": "kbuudvgcqhpqsviqbeqo",
"name": "quest-cms",
"organization_id": "org_xxxxxx",
"region": "ap-northeast-1",
"status": "ACTIVE_HEALTHY",
"created_at": "2024-01-15T10:00:00Z"
}
statusフィールドでプロジェクトの状態も確認できるため、ダウンしているプロジェクトの検知にも使えます。
Vercel Deployments API
Vercelには、プロジェクトのデプロイ履歴を取得するDeployments APIがあります。
GET https://api.vercel.com/v6/deployments
取得できるデプロイ情報
| フィールド | 説明 |
|---|---|
state |
デプロイ状態(READY, ERROR, BUILDING, QUEUED等) |
name |
プロジェクト名 |
url |
デプロイされたURL |
createdAt |
デプロイ開始時刻 |
buildingAt |
ビルド開始時刻 |
ready |
デプロイ完了時刻 |
meta.githubCommitMessage |
トリガーとなったGitコミットメッセージ |
meta.githubCommitRef |
ブランチ名 |
デプロイ失敗の検知
// 直近24時間のERROR状態デプロイを抽出
const failedDeploys = deployments.filter(d =>
d.state === 'ERROR' &&
new Date(d.createdAt) > new Date(Date.now() - 24
* 60
* 60
* 1000)
);
このAPIでどのコミットが原因でデプロイ失敗したかまで特定できるため、修正が容易になります。
Slack Incoming Webhooks
Slack Incoming Webhooksは、外部アプリからSlackにメッセージを送信するための仕組みです。
仕組み
- Slack Appを作成し、Incoming Webhookを有効化
- 送信先チャンネルを指定してWebhook URLを発行
- そのURLにHTTP POSTでメッセージを送信
- Slackチャンネルにメッセージが投稿される
送信できるメッセージ形式
// シンプルなテキスト
{ "text": "Hello, World!" }
// リッチなフォーマット(Block Kit)
{
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "🚨 セキュリティアラート" }
},
{
"type": "section",
"text": { "type": "mrkdwn", "text": "*ERROR*: 2件\n*WARN*: 5件" }
}
]
}
なぜWebhookを使うのか
| 方法 | メリット | デメリット |
|---|---|---|
| Slack Bot | 双方向通信可能、リアルタイム | 設定が複雑、サーバー必要 |
| Incoming Webhook | 設定が簡単、サーバー不要 | 送信のみ(受信不可) |
| Email通知 | どこでも受け取れる | 埋もれやすい、遅延あり |
今回のような「定期的に通知を送るだけ」のユースケースには、Webhookが最もシンプルです。
GitHub Actions(定期実行基盤)
GitHub Actionsは、GitHubが提供するCI/CDサービスで、cronスケジュールによる定期実行が可能です。
cronスケジュールの仕組み
on:
schedule:
- cron: '30 22 * * *' # 毎日UTC 22:30(JST 7:30)に実行
| フィールド | 意味 | 範囲 |
|---|---|---|
| 分 | 30 | 0-59 |
| 時 | 22 | 0-23 |
| 日 | 任意 | 1-31 |
| 月 | 任意 | 1-12 |
| 曜日 | 任意 | 0-6(日曜=0) |
注意点:
- cronはUTC基準(日本時間は+9時間)
- 正確な時刻での実行は保証されない(数分のズレあり)
- 無料プランでも月2,000分まで使用可能
なぜGitHub Actionsを選んだか
| サービス | 月間無料枠 | 設定の簡単さ | シークレット管理 |
|---|---|---|---|
| GitHub Actions | 2,000分 | ◎ 簡単 | ◎ 標準機能 |
| Vercel Cron | 無制限 | ○ 普通 | ○ 環境変数 |
| AWS Lambda | 100万リクエスト | △ 複雑 | △ Secrets Manager |
「追加コスト0」「設定が最も簡単」「シークレット管理が楽」という理由でGitHub Actionsを選択しました。
完成したシステム

全体の流れ
- 毎朝7:30にGitHub Actionsが起動
- Supabase Management APIで全プロジェクトのセキュリティ警告を取得
- Vercel APIで直近24時間のデプロイ失敗を取得
- 問題があればSlackに通知(なければ何もしない)
- 通知にはClaude Codeに貼り付けるだけの修正プロンプトを含める
技術スタック
| 技術 | 選定理由 |
|---|---|
| TypeScript | 型があると安心(Claude Codeも型を活用してくれる) |
| GitHub Actions | 無料枠で十分、シークレット管理が楽 |
| Slack Webhook | 無料、設定が簡単 |
実際のSlack通知

通知の構成
通知は3つのパートで構成されています:
1. ヘッダー
🚨 インフラ監視レポート
🕐 2025/12/17 7:30:00
2. サマリー(プロジェクトごとの件数)
📦 quest-cms: ERROR 0 / WARN 11
📦 ai-content-platform: ERROR 5 / WARN 9
🚀 corporate-site: デプロイ失敗 1件
3. 修正プロンプト(コピペ用)
🔧 対処方法
Claude Codeに以下を貼り付けてください:
セキュリティアラートを修正してください。
【Supabase: ai-content-platform】ERROR 5件
- Exposed Auth Users: admin_users_view
- RLS未設定: temp_data
...
この「修正プロンプト」が便利で、コピーしてClaude Codeに貼り付けるだけで修正が始まります。
運用1週間の実績
検出した問題
| 日付 | プロジェクト | 問題 | 対応時間 |
|---|---|---|---|
| 12/11 | ai-content-platform | auth_users_exposed × 1 | 5分 |
| 12/11 | ai-content-platform | security_definer_view × 2 | 10分 |
| 12/11 | ai-content-platform | rls_disabled × 2 | 15分 |
| 12/12 | quest-cms | search_path未設定 × 11 | 30分 |
| 12/13 | ai-content-platform | search_path未設定 × 9 | 25分 |
| 12/15 | corporate-site | Vercelデプロイ失敗 | 10分 |
合計:25件の問題を検出、約1.5時間で全て修正
修正の具体例
12/11に検出された auth_users_exposed の修正:
【Slackで届いた通知】
📦 ai-content-platform: ERROR 1 / WARN 9
- Exposed Auth Users: admin_users_view
【Claude Codeに貼り付けたプロンプト】
セキュリティアラートを修正してください。
【Supabase: ai-content-platform】ERROR 1件
- Exposed Auth Users: admin_users_view
【Claude Codeの対応】
1. admin_users_viewの定義を確認
2. auth.usersを直接参照していることを特定
3. ビューを削除するマイグレーションを作成
4. 代替としてRLS付きのクエリを提案
5分で完了。自分で調べてやってたら30分はかかってました。
よくあるセキュリティ警告と対処法
ERROR レベル(即座に対応すべき)
1. auth_users_exposed
意味:auth.usersテーブルが公開されている(ユーザー情報漏洩リスク)
対処法:
-- 問題のビューを特定して削除
DROP VIEW IF EXISTS public.admin_users_view;
-- 必要なら、RLS付きの安全な方法で再実装
2. rls_disabled_in_public
意味:RLS(行レベルセキュリティ)が無効なテーブルがある
対処法:
-- RLSを有効化
ALTER TABLE public.user_data ENABLE ROW LEVEL SECURITY;
-- ポリシーを設定
CREATE POLICY "Users can only see own data"
ON public.user_data FOR SELECT
USING (auth.uid() = user_id);
WARN レベル(早めに対応)
function_search_path_mutable
意味:関数のsearch_pathが未設定(スキーマ乗っ取りリスク)
なぜ危険? 悪意のあるユーザーが同名のスキーマを作成して、関数を乗っ取る可能性がある。
対処法:
-- 修正前(危険)
CREATE FUNCTION get_user_stats(user_id uuid)
RETURNS json AS $$ ... $$
LANGUAGE sql SECURITY DEFINER;
-- 修正後(安全)
CREATE FUNCTION get_user_stats(user_id uuid)
RETURNS json AS $$ ... $$
LANGUAGE sql SECURITY DEFINER
SET search_path = public, pg_temp; -- ← これを追加
主要なコード(抜粋)
全コードは長いので、ポイントだけ紹介します。
Supabaseスキャナーの核心部分
// セキュリティ警告を取得
async getSecurityAdvisors(projectId: string) {
const response = await fetch(
`https://api.supabase.com/v1/projects/${projectId}/advisors/security`,
{
headers: {
'Authorization': `Bearer ${this.accessToken}`,
}
}
);
const data = await response.json();
return data.result || [];
}
たったこれだけで、Supabaseの全セキュリティ警告が取得できます。
Slack通知のポイント
// 問題がなければ通知しない
if (!hasIssues) {
console.log('✅ 通知対象のアラートなし');
return; // 何もしない
}
「問題がなければ何も来ない」というのが運用上とても楽です。
GitHub Actions(定期実行)
on:
schedule:
- cron: '30 22 * * *' # UTC 22:30 = JST 7:30
構築にかかった時間
| 作業 | 時間 | 備考 |
|---|---|---|
| Claude Codeに相談 | 10分 | 構成を決定 |
| Supabaseスキャナー | 30分 | APIの仕様はClaudeが調査 |
| Vercelスキャナー | 20分 | 同上 |
| Slack通知 | 30分 | フォーマット調整に時間かかった |
| GitHub Actions | 15分 | cron設定ミスで10分ロス |
| テスト・修正 | 45分 | 3つの問題に遭遇 |
| 合計 | 約2.5時間 |
当初「半日」と言ってましたが、実際は2.5時間で完成しました。
この仕組みの効果
Before(導入前)
- Supabaseからのメールを見逃すことがある
- 問題に気づいても調査に時間がかかる
- 「まあいいか」と放置しがち
After(導入後)
- 毎朝Slackで確実に把握
- 修正プロンプト付きで即座に対応開始
- 「通知来てないからOK」という安心感
定量的な効果
- セキュリティ問題の検出から修正まで:平均15分(以前は数日放置も)
- 1週間で検出した問題:25件
- 修正にかかった総時間:約1.5時間
まとめ:非エンジニアでも作れる監視システム
この記事で紹介したシステムは、Claude Codeがあれば非エンジニアでも構築可能です。
ポイント:
- 「こういうことがしたい」と伝えれば、Claude Codeが構成を提案してくれる
- APIの仕様調査もClaude Codeがやってくれる
- エラーが出たら「これ出た」と貼り付ければ解決策を教えてくれる
「セキュリティ監視」と聞くと難しそうですが、実際にやったのは:
- Claude Codeに要件を伝える
- 出てきたコードを実行する
- エラーが出たらClaude Codeに相談する
これだけです。
セットアップ手順(これから作る人向け)
1. Slack Webhookの作成
まず、Slackで通知を受け取るためのWebhookを作成します。
- Slack APIにアクセス
- 「Create New App」→「From scratch」を選択
- App Nameを入力(例:
Security Monitor) - 「Incoming Webhooks」を有効化
- 「Add New Webhook to Workspace」でチャンネルを選択
- 生成されたWebhook URLをコピー
Webhook URLは https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX のような形式です。これを安全に保管してください。
2. Supabase Access Tokenの取得
- Supabase Dashboardにログイン
- 右上のアカウントアイコン → 「Account Settings」
- 「Access Tokens」タブを開く
- 「Generate New Token」をクリック
- 「No expiration」を選択(有効期限なし推奨)
- 生成されたトークンをコピー
注意:トークンは一度しか表示されません。必ずコピーして安全な場所に保存してください。
3. Vercel Access Tokenの取得(任意)
Vercelのデプロイ監視も行う場合:
- Vercel Dashboardにアクセス
- 「Create」をクリック
- Token Nameを入力、スコープは「Full Account」
- 生成されたトークンをコピー
4. GitHub Secretsの設定
GitHubリポジトリで秘密情報を管理します:
- リポジトリの「Settings」→「Secrets and variables」→「Actions」
- 「New repository secret」で以下を追加:
| Name | Value |
|---|---|
SUPABASE_ACCESS_TOKEN |
手順2でコピーしたトークン |
SLACK_WEBHOOK_URL |
手順1でコピーしたURL |
VERCEL_ACCESS_TOKEN |
手順3でコピーしたトークン(任意) |
5. 最初のテスト実行
GitHub Actionsの「Actions」タブから「Run workflow」で手動実行できます。
私:「手動で実行してみたい」
Claude:「GitHub Actionsのworkflow_dispatchを設定しておきました。
Actionsタブ → Security Check → Run workflow で実行できます」
初回実行時は、設定が正しいか確認するために手動実行をおすすめします。
応用編:もっと便利にする改善案
改善案1:エラー時だけ通知を赤くする
現在の実装では全て同じフォーマットですが、ERRORがある場合は目立たせたい:
// ERRORがある場合は赤い警告を追加
const hasErrors = supabaseResults.some(r =>
r.lints.some(l => l.level === 'ERROR')
);
if (hasErrors) {
lines.unshift('🔴 *重大なセキュリティ問題が検出されました*');
}
改善案2:修正後の確認リマインダー
修正したら、翌日に「本当に直ったか」確認したい:
私:「修正したあと、直ったか確認するリマインダーがほしい」
Claude:「以下の方法が考えられます:
1. 修正プロンプトに『修正後は手動実行で確認』と記載
2. ERRORが検出されたら翌日まで毎時チェック
3. 修正完了をSlackで報告 → 翌朝の通知で確認」
今は1の方法を採用しています。「修正したらすぐ手動実行」がシンプルで確実です。
改善案3:週次サマリーレポート
毎日の通知に加えて、週次で傾向を把握したい:
検討中の機能:
- 週間の検出件数推移
- 最も多い警告タイプ
- プロジェクトごとのセキュリティスコア
これはまだ実装していませんが、Claude Codeに「週次レポート機能を追加して」と言えば作ってくれるはずです。
よくある質問(FAQ)
Q: 無料で運用できますか?
A: はい、完全無料で運用できます。
- GitHub Actions:月2,000分まで無料(このスクリプトは1回1分未満)
- Slack Incoming Webhook:無料プランでも制限なし
- Supabase/Vercel API:利用制限なし
毎日実行しても月30分程度なので、無料枠を超えることはまずありません。
Q: 複数のSupabaseプロジェクトを監視できますか?
A: はい、自動で全プロジェクトをスキャンします。
Access Tokenに紐づいた全プロジェクトが対象です。特定のプロジェクトだけ除外したい場合は、スキャナーにフィルタを追加できます。
// 特定のプロジェクトを除外する例
const excludeProjects = ['test-project', 'sandbox'];
const projects = (await this.listProjects())
.filter(p => !excludeProjects.includes(p.name));
Q: 通知をメールで受け取れますか?
A: 可能ですが、Slackをおすすめします。
メールだと:
- 他のメールに埋もれる
- 「修正プロンプト」をコピペしづらい
- リアルタイム性が低い
Slackなら:
- 専用チャンネルで見逃さない
- コードブロックをそのままコピー可能
- スマホでも即座に確認できる
どうしてもメールがいい場合は、SlackNotifierをEmailNotifierに置き換えれば対応できます。
Q: セキュリティ警告が出たらすぐ修正すべき?
A: レベルによります。
| レベル | 緊急度 | 対応目安 |
|---|---|---|
| ERROR | 高 | 即日対応 |
| WARN | 中 | 1週間以内 |
| INFO | 低 | 余裕があるときに |
ERRORは「今すぐヤバい」、WARNは「いつか問題になるかも」、INFOは「ベストプラクティス的にはこうした方がいい」程度の違いです。
Q: GitHub Actions以外で定期実行できますか?
A: はい、いくつかの選択肢があります。
- Vercel Cron Jobs:Vercelユーザーなら設定が簡単
- AWS Lambda + EventBridge:AWSに慣れてるなら
- Google Cloud Functions + Cloud Scheduler:GCP派の方に
- 自前サーバーのcron:VPSを持ってるなら
GitHub Actionsを選んだ理由は「追加コスト0」「設定が最も簡単」だからです。
Q: 他のサービス(AWS、Cloudflare等)も監視できますか?
A: 同じ仕組みで拡張可能です。
私:「AWSのセキュリティも監視したい」
Claude:「AWS Security Hubを使えば同様の監視ができます。
AWSスキャナーを追加しましょうか?
必要な権限は以下です:
- securityhub:GetFindings
- securityhub:BatchGetSecurityControls」
監視対象を増やしたくなったら、Claude Codeに「◯◯も監視したい」と言えばスキャナーを追加してくれます。
トラブルシューティング
通知が来ない
確認ポイント:
- GitHub Actionsのログを確認(エラーが出てないか)
- Slack Webhook URLが正しいか
- 本当に問題がないだけかも(問題なしは通知されない)
私:「通知が来ない」
Claude:「以下を確認してください:
1. Actions → Security Check → 最新の実行ログを確認
2. '✅ 通知対象のアラートなし' と出てれば正常
3. エラーが出てればSlack Webhook URLを再確認」
403 Forbiddenエラー
原因:Access Tokenの権限不足または期限切れ
対処法:
- Supabase Dashboardで新しいトークンを発行
- 「No expiration」を選択
- GitHub Secretsを更新
レート制限エラー
原因:APIを短時間に叩きすぎ
対処法:
// リクエスト間に遅延を入れる
for (const project of projects) {
await this.getSecurityAdvisors(project.id);
await new Promise(r => setTimeout(r, 500)); // 500ms待機
}
この記事のまとめ
構築したシステム
Supabase × Vercel × GitHub Actions × Slackを組み合わせた、セキュリティ監視の自動通知システムを構築しました。
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ GitHub Actions │───▶│ Supabase API │───▶│ Slack │
│ (毎朝7:30) │ │ Vercel API │ │ (通知+修正 │
│ │ │ │ │ プロンプト) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
この記事で学べたこと
| トピック | 内容 |
|---|---|
| Supabase Security Advisors API | プロジェクトのセキュリティ状態を監査するAPI |
| Vercel Deployments API | デプロイ履歴と失敗を検知するAPI |
| Slack Incoming Webhooks | 外部からSlackに通知を送る仕組み |
| GitHub Actions cron | 定期実行の設定方法(UTC基準に注意) |
| よくあるセキュリティ警告 | RLS未設定、auth漏洩、search_path問題とその対処法 |
導入効果の振り返り
| 指標 | Before | After |
|---|---|---|
| セキュリティ問題の検知 | メール確認(見逃しあり) | 毎朝Slackで自動通知 |
| 問題発見から修正まで | 数日〜放置も | 平均15分 |
| 調査・対応の手間 | 毎回ゼロから調査 | 修正プロンプトをコピペするだけ |
次のステップ
この仕組みを応用して、さらに監視を拡張できます:
- AWS Security Hubとの連携でAWSリソースも監視
- Cloudflareのセキュリティアラート連携
- 週次レポートで傾向分析
- Slackコマンドで手動スキャン実行
「◯◯も監視したい」とClaude Codeに伝えれば、同じ構成で拡張できます。
参考リンク
著者について
てんちょー(合同会社QUEST 代表)
普段はSIerで経営企画部員として働きながら、週末起業で会社を運営。Claude Codeを活用して、複数のWebサービスを開発・運用中。
X (Twitter): @questceo_ai


