GitHub Secret Scanning API で実現する機密情報監視の自動化¶
この記事は朝の記事のフォローアップです
ゴール¶
- Secret Scanning API を使った定期監視スクリプトの実装
- 検出時の自動通知システム(Slack/Discord)の構築
- GitHub Actions での完全自動化と失敗時のリトライ戦略
アーキテクチャ概要¶
監視システムは以下の3要素で構成:
- API Poller: GitHub API で定期的にアラートを取得
- Notification Handler: 新規検出を Slack/Discord へ通知
- State Manager: 既知アラートの重複通知を防ぐ状態管理
実装ステップ¶
ステップ1: Python 監視スクリプトの実装¶
scripts/secret_scanner.py:
import os
import json
import requests
from datetime import datetime
from typing import List, Dict
class SecretScanner:
def __init__(self, token: str, repo: str):
self.token = token
self.repo = repo
self.api_base = f"https://api.github.com/repos/{repo}"
self.headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
self.state_file = ".scanner_state.json"
def get_alerts(self) -> List[Dict]:
"""未解決のシークレットアラートを取得"""
url = f"{self.api_base}/secret-scanning/alerts"
params = {"state": "open", "per_page": 100}
response = requests.get(url, headers=self.headers, params=params)
if response.status_code == 404:
return [] # Secret scanning not enabled
response.raise_for_status()
return response.json()
def filter_new_alerts(self, alerts: List[Dict]) -> List[Dict]:
"""新規アラートのみをフィルタリング"""
known_ids = self.load_state()
new_alerts = [a for a in alerts if a["number"] not in known_ids]
# 状態を更新
if new_alerts:
for alert in new_alerts:
known_ids.add(alert["number"])
self.save_state(known_ids)
return new_alerts
ステップ2: 通知ハンドラーの実装¶
class NotificationHandler:
def __init__(self, webhook_url: str, platform: str = "slack"):
self.webhook_url = webhook_url
self.platform = platform
def send_alert(self, alert: Dict) -> bool:
"""アラートを Slack/Discord に送信"""
if self.platform == "slack":
payload = self._format_slack_message(alert)
else:
payload = self._format_discord_message(alert)
response = requests.post(self.webhook_url, json=payload)
return response.status_code == 200
def _format_slack_message(self, alert: Dict) -> Dict:
return {
"text": f"🚨 機密情報が検出されました",
"attachments": [{
"color": "danger",
"fields": [
{"title": "Secret Type", "value": alert["secret_type"], "short": True},
{"title": "File", "value": alert["locations"][0]["path"], "short": True},
{"title": "Detected", "value": alert["created_at"], "short": False},
{"title": "URL", "value": alert["html_url"], "short": False}
]
}]
}
ステップ3: GitHub Actions ワークフローの設定¶
.github/workflows/secret-monitoring.yml:
name: Secret Scanning Monitor
on:
schedule:
- cron: '*/30 * * * *' # 30分ごと
workflow_dispatch: # 手動実行も可能
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install requests
- name: Run scanner with retry
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: |
for i in 1 2 3; do
python scripts/secret_scanner.py && break
echo "Attempt $i failed, retrying..."
sleep 10
done
ベンチマーク / 比較¶
| 監視方法 | 検出速度 | 誤検知率 | 運用コスト |
|---|---|---|---|
| 手動チェック | 24時間以上 | 高(見逃し多) | 高(人的工数) |
| Git hooks のみ | 即座 | 中(ローカル限定) | 低 |
| API 定期監視 | 30分以内 | 低(GitHub 検証済) | 極低(自動化) |
| API + Webhooks | リアルタイム | 最低 | 低(初期設定のみ) |
失敗パターンと回避策¶
| 症状 | 原因 | 回避策 |
|---|---|---|
| 404 エラー | Secret scanning 未有効 | リポジトリ設定で有効化 or graceful handling |
| Rate limit 超過 | API 呼び出し過多 | 間隔を 30分以上に調整、条件付きポーリング |
| 重複通知 | 状態管理の不備 | .scanner_state.json を Actions artifacts で永続化 |
| Webhook 失敗 | URL 期限切れ/権限不足 | エラー時の fallback 通知先を設定 |
自動化の拡張案¶
- 優先度判定: secret_type に基づく緊急度の自動分類
- 自動修正 PR: 検出時に
.gitignore更新 PR を自動作成 - Issue 作成: 各アラートに対応する GitHub Issue の自動起票
- メトリクス収集: 検出頻度を Datadog/CloudWatch に送信
- コンプライアンスレポート: 月次サマリーの自動生成
次のステップ¶
このガイドを基に、さらなるセキュリティ強化とプロダクション運用の最適化を進めてください。