Przejdź do treści
Infrastruktura & Technologia

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.

Mansoor Ahmed
Mansoor Ahmed
Head of Engineering 16 min czytania

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.

  1. Supabase Self-Hosting Runbook
  2. Next.js nad Supabase - bezpieczna eksploatacja
  3. Supabase Edge Functions - bezpieczne wdrożenie
  4. Trigger.dev Background Jobs - bezpieczna eksploatacja
  5. Claude Code jako kontrola bezpieczeństwa w workflow DevOps - ten artykuł
  6. 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 deterministyczneReguły runbookówAnaliza Claude
WejściePolecenia systemowe (nmap, grep)Pliki MarkdownOutput z warstw 1+2
WyjścieFakty (otwarty/zamknięty, obecny/brak)Stan docelowy (POWINIEN)Priorytetyzowany raport
CzęstotliwośćCodziennie (cron)Statyczna (aktualizacja przy zmianach)Cotygodniowo + przy PR
Fałszywe pozytywyBrak (obiektywne)Brak (zdefiniowane reguły)Możliwe (interpretacja)
Wykrywanie dryftuZnane wzorceBrak (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

  1. Supabase Self-Hosting Runbook
  2. Next.js nad Supabase - bezpieczna eksploatacja
  3. Supabase Edge Functions - bezpieczne wdrożenie
  4. Trigger.dev Background Jobs - bezpieczna eksploatacja
  5. Claude Code jako kontrola bezpieczeństwa w workflow DevOps - ten artykuł
  6. 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

Bert Gogolin

Dyrektor Generalny, Gosign

AI Governance Briefing

Enterprise AI, regulacje i infrastruktura - raz w miesiącu, bezpośrednio ode mnie.

Bez spamu. Możliwość rezygnacji w każdej chwili. Polityka prywatności

Claude Code Security DevOps CI/CD Automation
Udostępnij artykuł

Najczęściej zadawane pytania

Czy Claude Code zastępuje deterministyczne skanery bezpieczeństwa?

Nie. Claude Code uzupełnia deterministyczne kontrole, interpretując ich wyniki, rozpoznając powiązania i priorytetyzując rekomendacje. Skrypty niezawodnie znajdują znane wzorce, Claude rozpoznaje nieznane wzorce i dryft architektury.

Czy Claude Code może działać na serwerze produkcyjnym?

Nie. Claude Code działa wyłącznie na serwerze audytowym z dostępem tylko do odczytu. Skrypty deterministyczne zbierają dane z serwera produkcyjnego, Claude analizuje tylko tekstowy output.

Dlaczego Claude Code nie może mieć dostępu do Bash w CI?

Z nieograniczonym dostępem do Bash, Claude Code mógłby teoretycznie wykonywać dowolne polecenia na serwerze, nawet jeśli prompt żąda jedynie analizy. Ograniczenie do Read, Grep i Glob zapewnia, że Claude może tylko czytać i analizować, ale nie może wprowadzać zmian w systemie.