Claude Code como control de seguridad en el workflow DevOps
Runbook DevOps para Security Reviews automatizados con Claude Code: instalación, Custom Commands, scripts de auditoría e integración CI.
Los app stacks self-hosted modernos se componen de muchos componentes: Supabase Platform, capa de aplicación Next.js, Edge Functions, Background Jobs y APIs externas. Con cada componente aumenta la probabilidad de errores de configuración, fugas de secrets, políticas faltantes y endpoints no asegurados.
Los escáneres de seguridad tradicionales verifican reglas estáticas. Encuentran service_role en un archivo .env, pero no reconocen que una nueva Server Action carece del mismo ownership check que está presente en todas las demás Server Actions. Reportan puertos abiertos, pero no reconocen que un cambio de firewall la semana pasada junto con un nuevo contenedor ha abierto una vía de acceso no prevista.
Claude Code cierra esta brecha como capa de análisis contextual sobre todo el stack.
Claude Code no sustituye los checks determinísticos. Los complementa interpretando los resultados, reconociendo relaciones y priorizando recomendaciones.
Este runbook describe cómo se instala, configura e integra Claude Code de forma concreta en el workflow DevOps.
De un vistazo - Artículo 5 de 6 de la serie DevOps Runbook
- Claude Code solo en el servidor de auditoría
- Modelo de tres capas
- Custom Commands definen el alcance de la revisión
- Modo headless restringido a Read/Grep/Glob
- Auditoría cron semanal más revisiones de PR
Índice de la serie
Esta guía forma parte de nuestra serie de runbooks DevOps para app stacks self-hosted.
- Supabase Self-Hosting Runbook
- Next.js sobre Supabase de forma segura
- Supabase Edge Functions de forma segura
- Trigger.dev Background Jobs en producción segura
- Claude Code como control de seguridad en el workflow DevOps - este artículo
- Security Baseline para todo el stack
Los primeros cuatro artículos describen los componentes individuales. Este artículo describe la capa de control de seguridad sobre ellos.
Visión general de la arquitectura
Claude Code trabaja no en el servidor de producción, sino en el servidor de auditoría (véase Artículo 1). Tiene acceso de solo lectura a los datos que analiza.
Servidor de producción (supabase-prod)
|
+-- Supabase Stack
+-- Next.js App
+-- Edge Functions
+-- Trigger.dev
|
+---- SSH (read-only) ----> Servidor de auditoría (audit-runner)
|
+-- Checks determinísticos
| +-- Port Scans (nmap)
| +-- Firewall Diff (iptables-save)
| +-- Versiones de contenedores (docker images)
| +-- Estado RLS (psql)
| +-- npm audit
| +-- Checks de código basados en grep
|
+-- Claude Code (headless)
| +-- Analiza resultados de checks
| +-- Lee Git Diffs
| +-- Verifica configs contra runbooks
| +-- Genera informe priorizado
|
+-- Informe -> Equipo DevOps (la persona decide)
Claude Code no ejecuta cambios en el sistema de producción. Ni deployments, ni rotación de secrets, ni paradas de contenedores.
Comparación de las tres capas
| Propiedad | Verificaciones deterministas | Reglas de runbooks | Análisis Claude |
|---|---|---|---|
| Entrada | Comandos del sistema (nmap, grep) | Archivos Markdown | Output de las capas 1+2 |
| Salida | Hechos (abierto/cerrado, presente/ausente) | Estado objetivo (DEBE) | Informe priorizado |
| Frecuencia | Diaria (cron) | Estática (actualización con cambios) | Semanal + en PR |
| Falsos positivos | Ninguno (objetivo) | Ninguno (reglas definidas) | Posibles (interpretación) |
| Detección de drift | Patrones conocidos | Ninguno (referencia) | Patrones desconocidos |
Principio fundamental: Tres niveles de verificación de seguridad
Nivel 1: Checks determinísticos (scripts)
-> Resultados objetivos y repetibles
-> Ejemplo: "El puerto 5432 es accesible desde el exterior" = hecho
Nivel 2: Reglas de runbook (archivos Markdown)
-> Estado objetivo definido del stack
-> Ejemplo: "PostgreSQL solo debe escuchar en 10.0.1.10"
Nivel 3: Análisis contextual de Claude Code (headless)
-> Interpreta resultados, reconoce relaciones
-> Ejemplo: "El puerto 5432 está abierto Y el nuevo contenedor
tiene una conexión directa a la DB. Esto es un problema."
Los niveles se construyen uno sobre otro. Claude recibe los resultados del Nivel 1 y las reglas del Nivel 2 como input y genera a partir de ellos su review contextual.
Parte A - Configuración de Claude Code
A1 - Instalación y configuración en el servidor de auditoría
Implementación
Claude Code se instala en el servidor de auditoría, no en el servidor de producción.
# En el servidor audit-runner
# Instalar Node.js (si no está presente)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
apt-get install -y nodejs
# Instalar Claude Code
npm install -g @anthropic-ai/claude-code
# Configurar API Key
# API Key propio con límite de presupuesto para CI/CD
export ANTHROPIC_API_KEY="sk-ant-..."
# Persistir en .bashrc o .env para el audit-user
echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> /home/audit/.bashrc
Probar el modo headless:
# Test sencillo: ¿funciona Claude Code de forma no interactiva?
echo "Hello" | claude -p "Antworte mit OK wenn du das lesen kannst" \
--output-format text
# Expectativa: "OK" o confirmación similar
Condición verificable
# ¿Claude Code instalado?
claude --version
# Expectativa: número de versión
# ¿API Key configurado?
test -n "$ANTHROPIC_API_KEY" && echo "OK" || echo "FEHLT"
# ¿Funciona el modo headless?
claude -p "Sage nur: OK" --output-format text --max-turns 1 2>/dev/null
# Expectativa: "OK"
Escenario de fallo
Si Claude Code se ejecuta en el servidor de producción y tiene acceso a Bash allí, un prompt defectuoso podría teóricamente ejecutar comandos en el sistema de producción. En el servidor de auditoría, Claude Code solo tiene acceso a los informes recopilados y a las copias de configuración, no al sistema en vivo.
A2 - Configurar Custom Security Review Command
Implementación
Claude Code soporta Custom Commands mediante archivos Markdown en .claude/commands/. Estos Commands definen el contexto y las reglas de verificación para el Security Review.
# En el repositorio de infraestructura
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)
- Todo en infraestructura en la UE (p. ej. Hetzner, OVH, Scaleway)
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.
Condición verificable
# ¿Existe el Custom Command?
test -f .claude/commands/security-review.md && echo "OK" || echo "FEHLT"
# ¿Claude Code reconoce el command?
claude -p "/security-review" --max-turns 1 2>/dev/null | head -5
# Expectativa: Claude comienza con el análisis
A3 - CLAUDE.md como contexto del proyecto
Implementación
Claude Code lee automáticamente el archivo CLAUDE.md en el directorio del proyecto. Este archivo proporciona a Claude el contexto permanente sobre el stack.
# CLAUDE.md (en el root del repositorio de infraestructura)
## Stack-Überblick
Self-hosted Supabase + Next.js + Edge Functions + Trigger.dev v3
en infraestructura en la UE (p. ej. Hetzner, OVH, Scaleway).
## 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
Quien combine el enfoque CLAUDE.md con las reglas de seguridad del Artículo 2 obtiene una base de contexto completa para reviews automatizados.
Parte B - El workflow de auditoría completo
Aquí converge lo que los Artículos 1 a 4 han preparado. Cada artículo tiene sus propios scripts de verificación. El Artículo 5 los unifica y pasa la salida a Claude Code.
B1 - El script de auditoría completo
Implementación
Este script recopila todos los resultados de los checks determinísticos y los pasa a Claude Code en modo headless.
#!/bin/bash
# scripts/full-security-audit.sh
# Läuft auf dem audit-runner Server
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"
# -------------------------------------------
# EBENE 1: Deterministische Checks
# -------------------------------------------
echo -e "\n# Deterministische Check-Ergebnisse\n" >> "$REPORT_FILE"
# --- Infrastruktur (Artikel 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 (Artikel 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 (Artikel 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 (Artikel 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"
# --- Git Änderungen ---
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"
# -------------------------------------------
# EBENE 2: Runbook-Regeln (als Kontext)
# -------------------------------------------
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"
# -------------------------------------------
# EBENE 3: Claude Code Analyse
# -------------------------------------------
echo ""
echo "=== Deterministische Checks abgeschlossen ==="
echo "=== Starte Claude Code Analyse ==="
echo ""
# Claude Code im Headless Mode aufrufen
# --allowedTools einschränken: nur Lesen, kein Bash, kein Schreiben
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)
# Report speichern
CLAUDE_REPORT="${REPORT_DIR}/claude-review-${DATE}.md"
echo "$CLAUDE_OUTPUT" > "$CLAUDE_REPORT"
echo ""
echo "=== Claude Code Review abgeschlossen ==="
echo "Report: $CLAUDE_REPORT"
# Bei kritischen 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
Condición verificable
# ¿Script ejecutable?
test -x scripts/full-security-audit.sh && echo "OK" || echo "NICHT AUSFÜHRBAR"
# ¿Existe el último informe de auditoría?
ls -la /opt/audit/reports/claude-review-$(date +%Y-%m-%d).md 2>/dev/null
# Expectativa: archivo de hoy
# ¿El informe contiene las secciones esperadas?
grep -c "KRITISCH\|WARNUNG\|INFO" /opt/audit/reports/claude-review-$(date +%Y-%m-%d).md
# Expectativa: al menos 1
B2 - Cuándo se ejecuta la auditoría
Tres puntos de activación
1. Cron semanal (domingo 6:00 h)
-> Auditoría completa de todo el stack
-> Resultado: informe priorizado para la semana
2. En Pull Requests (CI/CD)
-> Solo los archivos modificados
-> Resultado: comentario de review en el PR
3. Ad-hoc (manual)
-> Tras incidentes, deployments importantes, cambios de infraestructura
-> Resultado: análisis inmediato
Cron semanal:
# crontab en el audit-runner
0 6 * * 0 /opt/audit/scripts/full-security-audit.sh >> /var/log/security-audit.log 2>&1
PR Review (pasar Git Diff a Claude):
#!/bin/bash
# scripts/pr-security-review.sh
# Wird vom CI bei jedem PR aufgerufen
DIFF=$(git diff origin/main...HEAD)
if [ -z "$DIFF" ]; then
echo "Kein Diff, kein Review nötig"
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
Review ad-hoc:
# Manuell nach einem Incident
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
Condición verificable
# ¿Cron Job activo?
crontab -l | grep "full-security-audit"
# Expectativa: entrada presente
# ¿Última auditoría hace menos de 8 días?
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 "Letzter Report: $AGE Tage alt"
[ "$AGE" -gt 8 ] && echo "WARNUNG: Audit überfällig"
fi
Parte C - Qué puede hacer Claude y qué no
C1 - Dónde Claude Code es especialmente fuerte
Claude reconoce relaciones que los checks determinísticos no pueden ver:
Detectar deriva arquitectónica: Los checks determinísticos encuentran que existe una nueva Edge Function. Claude reconoce que esa Function contiene lógica de negocio que pertenece a Next.js porque procesa input de usuario y transforma datos en lugar de recibir un evento externo.
Patrones a través de los límites de archivos:
Un grep encuentra que falta getUser() en una Server Action. Claude reconoce que esa Action es la única de 15 Actions a la que le falta el check, y que fue añadida la semana pasada en un commit que también modificó otros tres archivos que están todos correctos. Eso indica un descuido, no un problema sistemático.
Priorización: Los checks determinísticos producen una lista plana de 30 hallazgos. Claude los agrupa: “Los 5 hallazgos de service_role están todos en la Admin Library y son correctos. Los 2 checks de autenticación faltantes en los Route Handlers son el riesgo real, porque afectan a endpoints de API públicos.”
Contexto de configuración: Un port scan muestra que el puerto 8000 está abierto. Claude sabe por el contexto del stack (CLAUDE.md) que el puerto 8000 es el puerto interno de Kong, y verifica si debería escuchar solo en localhost.
C2 - Qué Claude Code no puede hacer y no debe hacer
Claude no puede escanear activamente. No puede realizar escaneos de red, verificar procesos en ejecución ni probar puertos desde el exterior. Eso lo hacen las herramientas determinísticas (nmap, ss, docker ps). Claude analiza su output.
Claude no debe escribir en producción. La restricción --allowedTools en el modo headless asegura que Claude solo pueda leer:
# CORRECTO: Solo herramientas de lectura permitidas
claude -p "..." --allowedTools "Read,Grep,Glob"
# INCORRECTO: Bash permitido = Claude puede ejecutar comandos arbitrarios
claude -p "..." --allowedTools "Read,Grep,Glob,Bash"
Cuando Bash es necesario (p. ej. para git log), permitir solo comandos específicos:
--allowedTools "Read,Grep,Glob,Bash(git log*),Bash(git diff*)"
Claude no es determinístico. El mismo input puede generar informes ligeramente diferentes. Por eso Claude no sustituye a los checks determinísticos. Interpreta sus resultados.
Estadística: Según el informe de OWASP de 2024, más del 34% de las brechas de seguridad resultan de errores de configuración, no de vulnerabilidades en el código, exactamente el tipo de problemas que el análisis contextual está diseñado para detectar.
Claude no conoce datos en tiempo real. Trabaja con los snapshots que se le proporcionan en el momento de la auditoría. Entre la auditoría y la lectura del informe, el estado puede haber cambiado.
C3 - Reglas de seguridad para Claude Code en CI
# En el servidor de auditoría: configuración de Claude Code
# 1. API Key propio con límite de presupuesto
# Key separado, no el key de desarrollo
# Presupuesto: máx. 50 USD/mes para CI Reviews
# 2. --allowedTools siempre restringido
# Nunca acceso Bash sin restricciones en scripts automatizados
# 3. --max-turns limitado
# Previene bucles infinitos con inputs confusos
# Recomendación: 3-5 para PR Reviews, 5-10 para Full Audits
# 4. Output siempre guardado en archivo
# No solo en stdout, para que el informe sea trazable
# 5. Claude Code no tiene acceso SSH a producción
# Los scripts determinísticos recopilan los datos
# Claude solo recibe la salida de texto para su análisis
Checklist de deployment
Instalación
[ ] Claude Code instalado en audit-runner
[ ] API Key configurado (key CI separado con límite de presupuesto)
[ ] Modo headless funciona (test con claude -p)
Configuración
[ ] .claude/commands/security-review.md creado
[ ] CLAUDE.md presente en el repositorio de infraestructura
[ ] --allowedTools restringido a Read,Grep,Glob
[ ] --max-turns limitado a 5-10
Automatización
[ ] Script de auditoría completo presente y ejecutable
[ ] Cron job semanal activo
[ ] Script de PR Review integrado en CI
[ ] Alerta configurada para hallazgos críticos
Seguridad
[ ] Claude Code se ejecuta SOLO en el audit-runner
[ ] Claude Code NO tiene acceso SSH a producción
[ ] Sin acceso Bash sin restricciones en --allowedTools
[ ] Los informes se almacenan y archivan
[ ] Límite de presupuesto configurado en el API Key
Conclusión
Claude Code no es un escáner de seguridad automático ni un sustituto de los checks determinísticos. Es un analista contextual que interpreta los resultados de escáneres y checks basados en grep, reconoce relaciones y prioriza recomendaciones.
El workflow es siempre el mismo: las herramientas determinísticas recopilan hechos, Claude Code los interpreta, una persona decide. Esto funciona porque cada nivel hace lo que mejor sabe hacer. Los scripts son fiables con patrones conocidos. Claude reconoce patrones desconocidos. Las personas toman decisiones.
La combinación de los scripts de verificación de los Artículos 1-4, el Custom Security Review Command y el cron de auditoría semanal da como resultado un control de seguridad que detecta tanto riesgos conocidos como inesperados.
Quien siga estos principios junto con una arquitectura Cert-Ready-by-Design construye seguridad verificable en lugar de auditorías a posteriori.
Listas de verificación de la serie
Prompts preparados para Claude Code. Cada lista de verificación comprueba automáticamente los puntos de seguridad del runbook correspondiente e informa APROBADO, ADVERTENCIA o CRÍTICO.
Índice de la serie
- Supabase Self-Hosting Runbook
- Next.js sobre Supabase de forma segura
- Supabase Edge Functions de forma segura
- Trigger.dev Background Jobs en producción segura
- Claude Code como control de seguridad en el workflow DevOps - este artículo
- Security Baseline para todo el stack
El siguiente y último artículo describe la Security Baseline para el stack completo, que reúne todas las reglas de los Artículos 1-5 en un único archivo verificable.

Bert Gogolin
Director General, Gosign
AI Governance Briefing
IA empresarial, regulación e infraestructura - una vez al mes, directamente de mi parte.