Claude Code jako kontrola bezpieczeństwa w workflow DevOps
Runbook DevOps dla automatycznych przeglądów bezpieczeństwa z Claude Code: instalacja, Custom Commands, skrypty audytowe i integracja CI.
Nowoczesne self-hosted stacki aplikacyjne składają się z wielu komponentów: Supabase Platform, warstwa Next.js, Edge Functions, Background Jobs i zewnętrzne API. Z każdym komponentem rośnie prawdopodobieństwo błędów konfiguracyjnych, wycieków sekretów, brakujących policies i niezabezpieczonych endpointów.
Tradycyjne skanery bezpieczeństwa sprawdzają statyczne reguły. Znajdują service_role w pliku .env, ale nie rozpoznają, że nowa Server Action nie ma tego samego sprawdzenia ownership, które jest obecne we wszystkich pozostałych Server Actions. Zgłaszają otwarte porty, ale nie rozpoznają, że zmiana firewalla w zeszłym tygodniu razem z nowym kontenerem otworzyła niezamierzoną ścieżkę dostępu.
Claude Code wypełnia tę lukę jako kontekstowa warstwa analityczna nad całym stackiem.
Claude Code nie zastępuje deterministycznych kontroli. Uzupełnia je, interpretując wyniki, rozpoznając powiązania i priorytetyzując rekomendacje.
Ten runbook opisuje, jak Claude Code jest konkretnie instalowany, konfigurowany i integrowany w workflow DevOps.
W skrócie - Artykuł 5 z 6 serii DevOps Runbook
- Claude Code tylko na serwerze audytowym
- Model trójwarstwowy
- Custom Commands definiują zakres przeglądu
- Tryb headless ograniczony do Read/Grep/Glob
- Cotygodniowy audyt cron plus przeglądy PR
Spis treści serii
Ten przewodnik jest częścią naszej serii runbooków DevOps dla self-hosted stacków aplikacyjnych.
- Supabase Self-Hosting Runbook
- Next.js nad Supabase - bezpieczna eksploatacja
- Supabase Edge Functions - bezpieczne wdrożenie
- Trigger.dev Background Jobs - bezpieczna eksploatacja
- Claude Code jako kontrola bezpieczeństwa w workflow DevOps - ten artykuł
- Security Baseline dla całego stacku
Pierwsze cztery artykuły opisują poszczególne komponenty. Ten artykuł opisuje warstwę kontroli bezpieczeństwa nad nimi.
Przegląd architektury
Claude Code działa nie na serwerze produkcyjnym, lecz na serwerze audytowym (patrz Artykuł 1). Ma dostęp tylko do odczytu danych, które analizuje.
Serwer produkcyjny (supabase-prod)
|
+-- Supabase Stack
+-- Next.js App
+-- Edge Functions
+-- Trigger.dev
|
+---- SSH (read-only) ----> Serwer audytowy (audit-runner)
|
+-- Kontrole deterministyczne
| +-- Port Scans (nmap)
| +-- Firewall Diff (iptables-save)
| +-- Wersje kontenerów (docker images)
| +-- Status RLS (psql)
| +-- npm audit
| +-- Kontrole kodu oparte na grep
|
+-- Claude Code (headless)
| +-- Analizuje wyniki kontroli
| +-- Czyta Git Diffy
| +-- Sprawdza konfiguracje względem runbooków
| +-- Tworzy priorytetyzowany raport
|
+-- Raport -> Zespół DevOps (człowiek decyduje)
Claude Code nie wykonuje żadnych zmian na systemie produkcyjnym. Żadnych deploymentów, żadnej rotacji sekretów, żadnych zatrzymań kontenerów.
Porównanie trzech warstw
| Właściwość | Kontrole deterministyczne | Reguły runbooków | Analiza Claude |
|---|---|---|---|
| Wejście | Polecenia systemowe (nmap, grep) | Pliki Markdown | Output z warstw 1+2 |
| Wyjście | Fakty (otwarty/zamknięty, obecny/brak) | Stan docelowy (POWINIEN) | Priorytetyzowany raport |
| Częstotliwość | Codziennie (cron) | Statyczna (aktualizacja przy zmianach) | Cotygodniowo + przy PR |
| Fałszywe pozytywy | Brak (obiektywne) | Brak (zdefiniowane reguły) | Możliwe (interpretacja) |
| Wykrywanie dryftu | Znane wzorce | Brak (referencja) | Nieznane wzorce |
Podstawowa zasada: Trzy poziomy kontroli bezpieczeństwa
Poziom 1: Kontrole deterministyczne (skrypty)
-> Obiektywne, powtarzalne wyniki
-> Przykład: "Port 5432 jest dostępny z zewnątrz" = fakt
Poziom 2: Reguły runbooków (pliki Markdown)
-> Zdefiniowany stan docelowy stacku
-> Przykład: "Postgres może nasłuchiwać tylko na 10.0.1.10"
Poziom 3: Analiza kontekstowa Claude Code (headless)
-> Interpretuje wyniki, rozpoznaje powiązania
-> Przykład: "Port 5432 jest otwarty I nowy kontener
ma bezpośrednie połączenie z DB. To jest problem."
Poziomy budują na sobie wzajemnie. Claude otrzymuje wyniki z poziomu 1 i reguły z poziomu 2 jako input i tworzy z nich swój kontekstowy przegląd.
Część A - Konfiguracja Claude Code
A1 - Instalacja i konfiguracja na serwerze audytowym
Implementacja
Claude Code jest instalowany na serwerze audytowym, nie na serwerze produkcyjnym.
# Na serwerze audit-runner
# Instalacja Node.js (jeśli nie jest zainstalowany)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
apt-get install -y nodejs
# Instalacja Claude Code
npm install -g @anthropic-ai/claude-code
# Konfiguracja API Key
# Osobny API Key z limitem budżetowym dla CI/CD
export ANTHROPIC_API_KEY="sk-ant-..."
# Utrwalenie w .bashrc lub .env dla użytkownika audit
echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> /home/audit/.bashrc
Test trybu headless:
# Prosty test: czy Claude Code działa nieinteraktywnie?
echo "Hello" | claude -p "Antworte mit OK wenn du das lesen kannst" \
--output-format text
# Oczekiwanie: "OK" lub podobne potwierdzenie
Sprawdzalny warunek
# Claude Code zainstalowany?
claude --version
# Oczekiwanie: numer wersji
# API Key ustawiony?
test -n "$ANTHROPIC_API_KEY" && echo "OK" || echo "BRAK"
# Tryb headless działa?
claude -p "Sage nur: OK" --output-format text --max-turns 1 2>/dev/null
# Oczekiwanie: "OK"
Scenariusz awarii
Jeśli Claude Code działa na serwerze produkcyjnym i ma tam dostęp do Bash, błędny prompt mógłby teoretycznie wykonać polecenia na systemie produkcyjnym. Na serwerze audytowym Claude Code ma dostęp tylko do zebranych raportów i kopii konfiguracji, nie do systemu live.
A2 - Konfiguracja Custom Security Review Command
Implementacja
Claude Code obsługuje Custom Commands przez pliki Markdown w .claude/commands/. Te Commands definiują kontekst i reguły kontroli dla przeglądu bezpieczeństwa.
# W repozytorium infrastruktury
mkdir -p .claude/commands
# .claude/commands/security-review.md
Du bist Security Reviewer für einen self-hosted Stack bestehend aus:
- Supabase (PostgreSQL, PostgREST, GoTrue, Kong, Edge Functions)
- Next.js (App-Schicht, Server Actions, Route Handler)
- Trigger.dev v3 (Background Jobs, self-hosted)
- Wszystko na infrastrukturze w UE (np. Hetzner, OVH)
Du erhältst den Output der deterministischen Security Checks und die
aktuellen Konfigurationsdateien.
Prüfe folgendes:
## Infrastruktur (Artikel 1)
- Sind unerwartete Ports von aussen erreichbar?
- Hat sich die Firewall gegenüber der Baseline geändert?
- Sind Container-Versionen gepinnt und aktuell?
- Ist das TLS-Zertifikat noch mindestens 14 Tage gültig?
- Liegt das letzte Backup weniger als 26 Stunden zurück?
## Next.js (Artikel 2)
- Taucht service_role in NEXT_PUBLIC Variablen oder im Client-Bundle auf?
- Haben alle Server Actions einen getUser() Auth Check?
- Haben alle Route Handler einen getUser() Auth Check?
- Existiert middleware.ts mit getUser() (nicht getSession())?
- Sind Security Headers in next.config.js gesetzt?
## Edge Functions (Artikel 3)
- Haben alle Webhook-Functions eine Signaturprüfung?
- Gibt es Functions mit Business-Logik statt Integrations-Logik?
- Ist CORS korrekt konfiguriert (kein Wildcard in Produktion)?
- Gibt es hardcoded Secrets im Function-Code?
## Trigger.dev (Artikel 4)
- Haben alle Tasks maxDuration und concurrencyLimit?
- Haben Tasks mit externen API-Calls Idempotency Keys?
- Nutzen Tasks nur die DB-Felder die sie brauchen (kein SELECT *)?
- Gibt es console.log statt dem Trigger.dev logger?
## Stackübergreifend
- Gibt es Architektur-Drift? (Business-Logik in Edge Functions,
Langläufer in Server Actions, etc.)
- Sind die Änderungen der letzten Woche konsistent mit der
bestehenden Architektur?
- Gibt es neue Tabellen ohne RLS?
- Gibt es Muster die auf systematische Probleme hindeuten?
Erstelle einen priorisierten Bericht:
- KRITISCH: sofort handeln (Daten-Leak möglich, Port offen, Secret exponiert)
- WARNUNG: diese Woche lösen (fehlende Checks, Drift, veraltete Packages)
- INFO: bei Gelegenheit verbessern (Code-Qualität, fehlende Tests)
Für jedes Finding: Was ist das Problem, warum ist es ein Risiko,
was ist die konkrete Lösung.
Sprawdzalny warunek
# Custom Command istnieje?
test -f .claude/commands/security-review.md && echo "OK" || echo "BRAK"
# Command jest rozpoznawany przez Claude Code?
claude -p "/security-review" --max-turns 1 2>/dev/null | head -5
# Oczekiwanie: Claude rozpoczyna analizę
A3 - CLAUDE.md jako kontekst projektu
Implementacja
Claude Code automatycznie czyta plik CLAUDE.md w katalogu projektu. Ten plik zapewnia Claude stały kontekst dotyczący stacku.
# CLAUDE.md (w katalogu głównym repozytorium infrastruktury)
## Stack-Überblick
Self-hosted Supabase + Next.js + Edge Functions + Trigger.dev v3
na infrastrukturze w UE (np. Hetzner, OVH).
## Server
- supabase-prod: 10.0.1.10 (Supabase, Next.js, Edge Functions)
- audit-runner: 10.0.1.11 (Security Checks, Claude Code, Monitoring)
- trigger-server: separater Docker-Stack für Trigger.dev v3
## Sicherheitsregeln
- service_role Key darf NUR in: lib/supabase/admin.ts und trigger/lib/supabase.ts
- NEXT_PUBLIC_* darf NUR enthalten: SUPABASE_URL und SUPABASE_ANON_KEY
- Alle public-Tabellen müssen RLS aktiviert haben
- Alle Server Actions und Route Handler müssen getUser() aufrufen
- Alle Webhook Edge Functions müssen Signaturen prüfen
- Alle Trigger.dev Tasks müssen maxDuration und concurrencyLimit haben
- PostgreSQL nur auf 10.0.1.10:5432 (internes Interface)
- Supabase Studio nicht von aussen erreichbar
- Trigger.dev Dashboard nicht von aussen erreichbar
## Deployment
- Infrastruktur wird nur über Git deployed (kein manuelles SSH-Editing)
- Edge Functions werden als Dateien in volumes/functions/ abgelegt
- Trigger.dev Tasks werden über npx trigger.dev deploy --self-hosted deployed
## Verzeichnisstruktur
- app/ = Next.js App (Server Actions, Route Handler, Pages)
- lib/supabase/ = Supabase Client Konfiguration
- middleware.ts = Auth Middleware
- volumes/functions/ = Supabase Edge Functions
- trigger/tasks/ = Trigger.dev Tasks
- infra/ = docker-compose, nginx/caddy, Firewall Configs
- scripts/ = Audit Scripts, Backup, Restore
- runbooks/ = Sicherheits-Runbooks
Kto łączy podejście CLAUDE.md z regułami bezpieczeństwa z artykułu 2, uzyskuje kompletną bazę kontekstową dla automatycznych przeglądów.
Część B - Kompletny workflow audytu
Tutaj łączy się to, co przygotowały artykuły 1 do 4. Każdy artykuł ma własne skrypty kontrolne. Artykuł 5 scala je i przekazuje output do Claude Code.
B1 - Kompletny skrypt audytowy
Implementacja
Ten skrypt zbiera wszystkie wyniki kontroli deterministycznych i przekazuje je do Claude Code w trybie headless.
#!/bin/bash
# scripts/full-security-audit.sh
# Działa na serwerze audit-runner
set -euo pipefail
PROD_HOST="10.0.1.10"
REPORT_DIR="/opt/audit/reports"
DATE=$(date +%Y-%m-%d)
REPORT_FILE="${REPORT_DIR}/audit-input-${DATE}.md"
mkdir -p "$REPORT_DIR"
echo "=== Gesamt-Security-Audit ${DATE} ===" | tee "$REPORT_FILE"
# -------------------------------------------
# POZIOM 1: Kontrole deterministyczne
# -------------------------------------------
echo -e "\n# Deterministische Check-Ergebnisse\n" >> "$REPORT_FILE"
# --- Infrastruktura (Artykuł 1) ---
echo "## Infrastruktur" >> "$REPORT_FILE"
echo "### Offene Ports (extern)" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
nmap -p 22,80,443,3000,3040,5432,5433,8000,9000 app.example.com \
--open -oG - 2>/dev/null >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### Firewall Diff gegen Baseline" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "iptables-save" | \
diff /opt/baselines/firewall-baseline.txt - >> "$REPORT_FILE" 2>&1 || true
echo '```' >> "$REPORT_FILE"
echo "### Container Status" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "docker compose ps --format 'table {{.Name}}\t{{.Status}}\t{{.Image}}'" \
>> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
echo "### TLS Zertifikat" >> "$REPORT_FILE"
CERT_EXPIRY=$(echo | openssl s_client -connect app.example.com:443 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
CERT_EPOCH=$(date -d "$CERT_EXPIRY" +%s 2>/dev/null || echo 0)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (CERT_EPOCH - NOW_EPOCH) / 86400 ))
echo "Ablauf: ${CERT_EXPIRY} (${DAYS_LEFT} Tage)" >> "$REPORT_FILE"
echo "### Backup Status" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "ls -lh /opt/backups/*.gpg 2>/dev/null | tail -3" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### RLS Status" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "docker compose exec -T postgres psql -U postgres -c \
\"SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename;\"" \
>> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
echo "### Disk Usage" >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "df -h / | tail -1" >> "$REPORT_FILE"
# --- Next.js (Artykuł 2) ---
echo -e "\n## Next.js App-Schicht" >> "$REPORT_FILE"
echo "### service_role im Client Code" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && grep -rn 'SERVICE_ROLE\|service_role' app/ \
--include='*.ts' --include='*.tsx' | grep -v 'lib/supabase/admin.ts' | grep -v node_modules" \
>> "$REPORT_FILE" 2>&1 || echo "Keine Treffer" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### NEXT_PUBLIC mit Secrets" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && grep 'NEXT_PUBLIC_' .env* 2>/dev/null | \
grep -iE 'service_role|secret|private|database'" \
>> "$REPORT_FILE" 2>&1 || echo "Keine Treffer" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### Server Actions ohne Auth" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && for file in \$(grep -rl \"'use server'\" app/ --include='*.ts'); do
if ! grep -q 'getUser' \"\$file\"; then
echo \"WARNUNG: \$file\"
fi
done" >> "$REPORT_FILE" 2>&1 || echo "Keine Treffer" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### Route Handler ohne Auth" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && for file in \$(find app/api -name 'route.ts' 2>/dev/null); do
if ! grep -q 'getUser' \"\$file\"; then
echo \"WARNUNG: \$file\"
fi
done" >> "$REPORT_FILE" 2>&1 || echo "Keine Treffer" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
echo "### npm audit" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && npm audit --audit-level=high 2>&1 | tail -20" \
>> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
# --- Edge Functions (Artykuł 3) ---
echo -e "\n## Edge Functions" >> "$REPORT_FILE"
echo "### Webhook Functions ohne Signaturprüfung" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "for dir in /opt/supabase/volumes/functions/*-webhook/; do
[ -d \"\$dir\" ] || continue
name=\$(basename \"\$dir\")
if ! grep -qE 'signature|verify|hmac|crypto' \"\$dir/index.ts\" 2>/dev/null; then
echo \"KRITISCH: \$name hat keine Signaturprüfung\"
else
echo \"OK: \$name\"
fi
done" >> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
echo "### Hardcoded Secrets in Functions" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "grep -rn 'sk_live\|sk_test\|whsec_\|Bearer ey' \
/opt/supabase/volumes/functions/ --include='*.ts' 2>/dev/null" \
>> "$REPORT_FILE" 2>&1 || echo "Keine Treffer" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
# --- Trigger.dev (Artykuł 4) ---
echo -e "\n## Trigger.dev Tasks" >> "$REPORT_FILE"
echo "### Tasks ohne maxDuration" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && for file in trigger/tasks/*.ts; do
name=\$(basename \"\$file\" .ts)
if ! grep -q 'maxDuration' \"\$file\" 2>/dev/null; then
echo \"WARNUNG: \$name\"
fi
done" >> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
echo "### Tasks ohne Concurrency Limit" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && for file in trigger/tasks/*.ts; do
name=\$(basename \"\$file\" .ts)
if ! grep -qE 'concurrencyLimit|queue:' \"\$file\" 2>/dev/null; then
echo \"WARNUNG: \$name\"
fi
done" >> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
# --- Zmiany w kodzie ---
echo -e "\n## Code-Änderungen (letzte 7 Tage)" >> "$REPORT_FILE"
echo '```' >> "$REPORT_FILE"
ssh deploy@${PROD_HOST} "cd /opt/app && git log --oneline --since='7 days ago'" \
>> "$REPORT_FILE" 2>&1
ssh deploy@${PROD_HOST} "cd /opt/app && git diff HEAD~10 --stat 2>/dev/null" \
>> "$REPORT_FILE" 2>&1
echo '```' >> "$REPORT_FILE"
# -------------------------------------------
# POZIOM 2: Reguły runbooków (jako kontekst)
# -------------------------------------------
echo -e "\n# Aktive Runbook-Regeln\n" >> "$REPORT_FILE"
cat runbooks/security-baseline.md >> "$REPORT_FILE" 2>/dev/null || \
echo "security-baseline.md nicht gefunden" >> "$REPORT_FILE"
# -------------------------------------------
# POZIOM 3: Analiza Claude Code
# -------------------------------------------
echo ""
echo "=== Deterministische Checks abgeschlossen ==="
echo "=== Starte Claude Code Analyse ==="
echo ""
# Wywołanie Claude Code w trybie headless
# --allowedTools ograniczone: tylko odczyt, bez Bash, bez zapisu
CLAUDE_OUTPUT=$(cat "$REPORT_FILE" | claude -p \
"Du erhältst den vollständigen Security-Audit-Report unseres self-hosted Stacks.
Analysiere ihn gemäss den Regeln in .claude/commands/security-review.md.
Erstelle einen priorisierten Bericht mit KRITISCH / WARNUNG / INFO.
Für jedes Finding: Problem, Risiko, konkrete Lösung." \
--allowedTools "Read,Grep,Glob" \
--append-system-prompt "Du bist ein Senior Security Engineer. Antworte auf Deutsch. Sei konkret und priorisiere strikt." \
--output-format text \
--max-turns 5 \
2>/dev/null)
# Zapis raportu
CLAUDE_REPORT="${REPORT_DIR}/claude-review-${DATE}.md"
echo "$CLAUDE_OUTPUT" > "$CLAUDE_REPORT"
echo ""
echo "=== Claude Code Review abgeschlossen ==="
echo "Report: $CLAUDE_REPORT"
# Przy krytycznych findings: alert
if echo "$CLAUDE_OUTPUT" | grep -qi "KRITISCH"; then
echo "$CLAUDE_OUTPUT" | mail -s "KRITISCH: Security Review ${DATE}" ops@example.com
echo "Alert gesendet an ops@example.com"
fi
Sprawdzalny warunek
# Skrypt jest wykonywalny?
test -x scripts/full-security-audit.sh && echo "OK" || echo "NIE WYKONYWALNY"
# Ostatni raport audytowy istnieje?
ls -la /opt/audit/reports/claude-review-$(date +%Y-%m-%d).md 2>/dev/null
# Oczekiwanie: plik z dzisiejszą datą
# Raport zawiera oczekiwane sekcje?
grep -c "KRITISCH\|WARNUNG\|INFO" /opt/audit/reports/claude-review-$(date +%Y-%m-%d).md
# Oczekiwanie: co najmniej 1
B2 - Kiedy audyt jest uruchamiany
Trzy punkty wyzwalania
1. Cotygodniowy Cron (niedziela 6:00)
-> Pełny audyt całego stacku
-> Wynik: priorytetyzowany raport na tydzień
2. Przy Pull Requestach (CI/CD)
-> Tylko zmienione pliki
-> Wynik: komentarz review do PR
3. Ad-hoc (ręcznie)
-> Po incydentach, dużych deploymentach, zmianach infrastruktury
-> Wynik: natychmiastowa analiza
Cotygodniowy Cron:
# crontab na serwerze audit-runner
0 6 * * 0 /opt/audit/scripts/full-security-audit.sh >> /var/log/security-audit.log 2>&1
PR Review (Git Diff przekierowany do Claude):
#!/bin/bash
# scripts/pr-security-review.sh
# Wywoływany przez CI przy każdym PR
DIFF=$(git diff origin/main...HEAD)
if [ -z "$DIFF" ]; then
echo "Brak diffa, review nie jest potrzebny"
exit 0
fi
echo "$DIFF" | claude -p \
"Review diesen Git Diff auf Sicherheitsprobleme.
Prüfe insbesondere:
- service_role Nutzung in Client-Code
- Server Actions ohne Auth Check
- Edge Functions ohne Signaturprüfung
- Trigger.dev Tasks ohne maxDuration
- Hardcoded Secrets
- Neue API Endpoints ohne Rate Limiting
Antworte NUR wenn du ein konkretes Problem findest.
Wenn alles in Ordnung ist, sage: Keine Sicherheitsprobleme gefunden." \
--allowedTools "Read,Grep,Glob" \
--output-format text \
--max-turns 3
Ad-hoc Review:
# Ręcznie po incydencie
cd /opt/infra-repo
claude -p "Prüfe den aktuellen Zustand des Repositories auf Sicherheitsprobleme. \
Fokus auf die letzten 5 Commits." \
--allowedTools "Read,Grep,Glob,Bash(git log*),Bash(git diff*)" \
--max-turns 10
Sprawdzalny warunek
# Cron Job aktywny?
crontab -l | grep "full-security-audit"
# Oczekiwanie: wpis obecny
# Ostatni audyt mniej niż 8 dni temu?
LAST_REPORT=$(ls -t /opt/audit/reports/claude-review-*.md 2>/dev/null | head -1)
if [ -n "$LAST_REPORT" ]; then
AGE=$(( ($(date +%s) - $(stat -c %Y "$LAST_REPORT")) / 86400 ))
echo "Ostatni raport: $AGE dni temu"
[ "$AGE" -gt 8 ] && echo "OSTRZEŻENIE: Audyt zaległy"
fi
Część C - Co Claude potrafi, a czego nie
C1 - Gdzie Claude Code jest szczególnie skuteczny
Claude rozpoznaje powiązania, których kontrole deterministyczne nie są w stanie wykryć:
Rozpoznawanie dryftu architektury: Kontrole deterministyczne znajdują nową Edge Function. Claude rozpoznaje, że ta funkcja zawiera logikę biznesową, która powinna znajdować się w Next.js, ponieważ przetwarza dane wejściowe użytkownika i transformuje dane zamiast odbierać zewnętrzne zdarzenie.
Wzorce wykraczające poza granice plików:
grep znajduje brak getUser() w jednej Server Action. Claude rozpoznaje, że ta Action jest jedyną z 15 Actions, w której brakuje tego sprawdzenia, i że została dodana w zeszłym tygodniu w commicie, który zmienił również trzy inne pliki - wszystkie poprawnie. To wskazuje na przeoczenie, nie na problem systemowy.
Priorytetyzacja: Kontrole deterministyczne tworzą płaską listę 30 findings. Claude grupuje je: “5 findings dotyczących service_role jest w bibliotece Admin i jest poprawnych. 2 brakujące kontrole Auth w Route Handlerach to rzeczywiste ryzyko, ponieważ dotyczą publicznych endpointów API.”
Kontekst konfiguracyjny: Skan portów pokazuje, że port 8000 jest otwarty. Claude wie z kontekstu stacku (CLAUDE.md), że port 8000 to wewnętrzny port Kong, i sprawdza, czy powinien nasłuchiwać tylko na localhost.
C2 - Czego Claude Code nie potrafi i czego nie wolno mu robić
Claude nie potrafi aktywnie skanować. Nie jest w stanie przeprowadzać skanów sieciowych, sprawdzać działających procesów ani testować portów z zewnątrz. To robią narzędzia deterministyczne (nmap, ss, docker ps). Claude analizuje ich output.
Claude nie wolno zapisywać na produkcji. Ograniczenie --allowedTools w trybie headless zapewnia, że Claude może tylko czytać:
# POPRAWNIE: dozwolone tylko narzędzia do odczytu
claude -p "..." --allowedTools "Read,Grep,Glob"
# ŹŁLE: Bash dozwolony = Claude może wykonywać dowolne polecenia
claude -p "..." --allowedTools "Read,Grep,Glob,Bash"
Jeśli Bash jest potrzebny (np. dla git log), dozwalaj tylko konkretne polecenia:
--allowedTools "Read,Grep,Glob,Bash(git log*),Bash(git diff*)"
Claude nie jest deterministyczny. Ten sam input może prowadzić do nieco różnych raportów. Dlatego Claude nie zastępuje deterministycznych kontroli. Interpretuje ich wyniki.
Statystyka: Zgodnie z raportem OWASP z 2024 roku ponad 34% naruszeń bezpieczeństwa wynika z błędów konfiguracyjnych, a nie z luk w kodzie - dokładnie ten typ problemów, do którego wykrywania przeznaczona jest kontekstowa analiza.
Claude nie zna danych w czasie rzeczywistym. Pracuje z migawkami, które zostały mu przekazane w momencie audytu. Między audytem a lekturą raportu stan mógł się zmienić.
C3 - Reguły bezpieczeństwa dla Claude Code w CI
# Na serwerze audytowym: konfiguracja Claude Code
# 1. Osobny API Key z limitem budżetowym
# Odrębny klucz, nie klucz dewelopera
# Budżet: maks. 50 USD/miesiąc na przeglądy CI
# 2. --allowedTools zawsze ograniczaj
# Nigdy nieograniczonego dostępu do Bash w zautomatyzowanych skryptach
# 3. --max-turns ogranicz
# Zapobiega nieskończonym pętlom przy mylących inputach
# Rekomendacja: 3-5 dla przeglądów PR, 5-10 dla pełnych audytów
# 4. Output zawsze zapisuj do pliku
# Nie tylko na stdout, aby raport pozostał udokumentowany
# 5. Claude Code nie ma dostępu SSH do produkcji
# Skrypty deterministyczne zbierają dane
# Claude otrzymuje tylko tekstowy output do analizy
Lista kontrolna deploymentu
Instalacja
[ ] Claude Code zainstalowany na audit-runner
[ ] API Key skonfigurowany (osobny klucz CI z limitem budżetowym)
[ ] Tryb headless działa (test z claude -p)
Konfiguracja
[ ] .claude/commands/security-review.md utworzony
[ ] CLAUDE.md w repozytorium infrastruktury obecny
[ ] --allowedTools ograniczone do Read,Grep,Glob
[ ] --max-turns ograniczone do 5-10
Automatyzacja
[ ] Kompletny skrypt audytowy obecny i wykonywalny
[ ] Cotygodniowy Cron Job aktywny
[ ] Skrypt PR Review zintegrowany w CI
[ ] Alert przy krytycznych findings skonfigurowany
Bezpieczeństwo
[ ] Claude Code działa TYLKO na audit-runner
[ ] Claude Code NIE MA dostępu SSH do produkcji
[ ] Brak nieograniczonego dostępu Bash w --allowedTools
[ ] Raporty są zapisywane i archiwizowane
[ ] Limit budżetowy na API Key ustawiony
Podsumowanie
Claude Code nie jest automatycznym skanerem bezpieczeństwa i nie zastępuje deterministycznych kontroli. Jest kontekstowym analitykiem, który interpretuje wyniki skanerów i kontroli grep, rozpoznaje powiązania i priorytetyzuje rekomendacje.
Workflow jest zawsze taki sam: narzędzia deterministyczne zbierają fakty, Claude Code je interpretuje, człowiek decyduje. Działa to, ponieważ każdy poziom robi to, w czym jest najlepszy. Skrypty są niezawodne przy znanych wzorcach. Claude rozpoznaje nieznane wzorce. Ludzie podejmują decyzje.
Połączenie skryptów kontrolnych z artykułów 1-4, Custom Security Review Command i cotygodniowego Cron audytu daje kontrolę bezpieczeństwa, która wykrywa zarówno znane, jak i nieoczekiwane ryzyka.
Kto stosuje te zasady razem z architekturą Cert-Ready by Design, buduje weryfikowalne bezpieczeństwo zamiast audytów po fakcie.
Listy kontrolne audytu serii
Przygotowane prompty dla Claude Code. Każda lista kontrolna automatycznie weryfikuje punkty bezpieczeństwa danego runbooka i zgłasza ZALICZONY, OSTRZEŻENIE lub KRYTYCZNY.
Spis treści serii
- Supabase Self-Hosting Runbook
- Next.js nad Supabase - bezpieczna eksploatacja
- Supabase Edge Functions - bezpieczne wdrożenie
- Trigger.dev Background Jobs - bezpieczna eksploatacja
- Claude Code jako kontrola bezpieczeństwa w workflow DevOps - ten artykuł
- Security Baseline dla całego stacku
Kolejny i ostatni artykuł opisuje Security Baseline dla całego stacku, która scala wszystkie reguły z artykułów 1-5 w jednym weryfikowalnym pliku.

Bert Gogolin
Dyrektor Generalny, Gosign
AI Governance Briefing
Enterprise AI, regulacje i infrastruktura - raz w miesiącu, bezpośrednio ode mnie.