feat: refactor 30+ skills to Anthropic progressive disclosure pattern
- All SKILL.md files now <500 lines (avg reduction 69%) - Detailed content extracted to references/ subdirectories - Frontmatter standardised: only name + description (Anthropic standard) - New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator - Design skills: anti-slop guidelines, premium-proposals reference - Removed non-standard frontmatter fields (triggers, version, author, category) Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao, core-tools, negocio, perfex-dev, wordpress, design-media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
320
infraestrutura/skills/security-check/SKILL.md
Normal file
320
infraestrutura/skills/security-check/SKILL.md
Normal file
@@ -0,0 +1,320 @@
|
||||
---
|
||||
name: security-check
|
||||
description: Auditoria de seguranca de infraestrutura — certificados SSL, portas abertas, actualizacoes pendentes, backups recentes, CSF/firewall e email security. Score por servidor.
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /security-check v1.0 (infraestrutura)
|
||||
|
||||
Auditoria de seguranca dos servidores Descomplicar. Verifica SSL, portas, actualizacoes, backups, firewall e email security.
|
||||
|
||||
> **Auditoria de dependencias de codigo:** usar `/dep-audit` (plugin dev-tools).
|
||||
|
||||
**Referencia:** PROC-Security-Audit-API-Keys.md | PROC-Backup-Sistema.md | Memory: `infra.md`, `cwp-ssl-autorenew-fix.md`
|
||||
|
||||
---
|
||||
|
||||
## Servidores Alvo
|
||||
|
||||
| Alias | Host | IP | SO | Firewall | Gestor SSL |
|
||||
|-------|------|----|----|----------|------------|
|
||||
| server | server.descomplicar.pt | 176.9.3.158 | CentOS (CWP) | CSF v15 | acme.sh |
|
||||
| easy | qibspu.easypanel.host | 178.63.18.51 | Ubuntu 24.04 | — | EasyPanel/Traefik |
|
||||
| gateway | mcp-hub.descomplicar.pt | — | — | — | nginx/acme |
|
||||
|
||||
---
|
||||
|
||||
## Modos de Execucao
|
||||
|
||||
| Comando | Descricao |
|
||||
|---------|-----------|
|
||||
| `/security-check` | Auditoria completa (todos os servidores, todos os checks) |
|
||||
| `/security-check server` | Apenas servidor CWP |
|
||||
| `/security-check easy` | Apenas EasyPanel |
|
||||
| `/security-check ssl` | Apenas certificados SSL (todos os servidores) |
|
||||
| `/security-check quick` | Resumo rapido: SSL a expirar + backups + firewall |
|
||||
|
||||
---
|
||||
|
||||
## Protocolo de Execucao
|
||||
|
||||
### Check 1: Certificados SSL (server)
|
||||
|
||||
```bash
|
||||
# Executar via mcp__ssh-unified__ssh_execute(server="server")
|
||||
|
||||
# Listar todos os certs e datas de expiracao
|
||||
for dir in /root/.acme.sh/cwp_certs/*_ecc; do
|
||||
domain=$(basename "$dir" | sed 's/_ecc$//')
|
||||
cert="$dir/${domain}.cer"
|
||||
if [ -f "$cert" ]; then
|
||||
expiry=$(openssl x509 -enddate -noout -in "$cert" 2>/dev/null | cut -d= -f2)
|
||||
days=$(( ($(date -d "$expiry" +%s) - $(date +%s)) / 86400 ))
|
||||
if [ "$days" -lt 15 ]; then
|
||||
echo "CRITICAL $domain expires in ${days}d ($expiry)"
|
||||
elif [ "$days" -lt 30 ]; then
|
||||
echo "WARN $domain expires in ${days}d ($expiry)"
|
||||
else
|
||||
echo "OK $domain expires in ${days}d"
|
||||
fi
|
||||
fi
|
||||
done | sort
|
||||
```
|
||||
|
||||
**Thresholds:**
|
||||
- **OK:** >30 dias para expirar
|
||||
- **WARN:** 15-30 dias
|
||||
- **CRITICAL:** <15 dias
|
||||
|
||||
### Check 2: Portas Abertas (server)
|
||||
|
||||
```bash
|
||||
# Portas a escutar no servidor CWP
|
||||
ss -tlnp | awk 'NR>1 {print $4}' | sed 's/.*://' | sort -n | uniq
|
||||
|
||||
# Portas esperadas (CWP padrao):
|
||||
# 22(SSH) 25(SMTP) 80(HTTP) 110(POP3) 143(IMAP) 443(HTTPS)
|
||||
# 465(SMTPS) 587(Submission) 993(IMAPS) 995(POP3S)
|
||||
# 2031(CWP) 2087(CWP Admin) 3306(MySQL)
|
||||
# 8443(CWP SSL) 9443(SSH alternativo)
|
||||
EXPECTED="22 25 80 110 143 443 465 587 993 995 2031 2087 3306 8443 9443"
|
||||
|
||||
# Comparar: portas abertas que NAO estao na lista esperada
|
||||
ss -tlnp | awk 'NR>1 {print $4}' | sed 's/.*://' | sort -n | uniq | while read port; do
|
||||
if ! echo "$EXPECTED" | grep -qw "$port"; then
|
||||
proc=$(ss -tlnp | grep ":${port} " | sed 's/.*users:(("//' | cut -d'"' -f1)
|
||||
echo "UNEXPECTED :${port} ($proc)"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Check 3: Actualizacoes Pendentes
|
||||
|
||||
```bash
|
||||
# CWP Server (CentOS/dnf)
|
||||
# mcp__ssh-unified__ssh_execute(server="server")
|
||||
dnf check-update --quiet 2>/dev/null | grep -v "^$" | wc -l
|
||||
# Se >0: listar security updates
|
||||
dnf updateinfo list security 2>/dev/null | tail -10
|
||||
|
||||
# EasyPanel (Ubuntu/apt)
|
||||
# mcp__ssh-unified__ssh_execute(server="easy")
|
||||
apt list --upgradable 2>/dev/null | grep -c upgradable
|
||||
# Se >0: listar security updates
|
||||
apt list --upgradable 2>/dev/null | grep -i secur
|
||||
```
|
||||
|
||||
**Thresholds:**
|
||||
- **OK:** 0 security updates pendentes
|
||||
- **WARN:** 1-5 security updates
|
||||
- **CRITICAL:** >5 security updates OU kernel update pendente
|
||||
|
||||
### Check 4: Backups Recentes (server)
|
||||
|
||||
```bash
|
||||
# mcp__ssh-unified__ssh_execute(server="server")
|
||||
|
||||
echo "=== MySQL Daily ==="
|
||||
ls -lt /home/backup/mysql/daily/ 2>/dev/null | head -3
|
||||
latest_mysql=$(find /home/backup/mysql/daily/ -name "*.sql.gz" -mtime -2 2>/dev/null | wc -l)
|
||||
echo "BDs com backup <48h: $latest_mysql"
|
||||
|
||||
echo "=== Monthly ==="
|
||||
ls -lt /home/backup/monthly/ 2>/dev/null | head -5
|
||||
|
||||
echo "=== Rsync Easy->Server ==="
|
||||
# Verificar ultimo rsync (Easy replica para Server as 06:00)
|
||||
ls -lt /gordito/backup-easy/ 2>/dev/null | head -3 || echo "path nao existe"
|
||||
|
||||
echo "=== Idade ultimo backup ==="
|
||||
newest=$(find /home/backup/ -type f -name "*.gz" -printf '%T@\n' 2>/dev/null | sort -rn | head -1)
|
||||
if [ -n "$newest" ]; then
|
||||
age_hours=$(echo "scale=1; ($(date +%s) - $newest) / 3600" | bc)
|
||||
echo "Backup mais recente: ${age_hours}h atras"
|
||||
fi
|
||||
```
|
||||
|
||||
**Thresholds:**
|
||||
- **OK:** backup MySQL <48h, monthly <35 dias
|
||||
- **WARN:** backup MySQL 48-72h, monthly 35-60 dias
|
||||
- **CRITICAL:** backup MySQL >72h, monthly >60 dias
|
||||
|
||||
### Check 5: Firewall CSF (server)
|
||||
|
||||
```bash
|
||||
# mcp__ssh-unified__ssh_execute(server="server")
|
||||
|
||||
echo "=== CSF Status ==="
|
||||
csf -v
|
||||
csf -l | head -5
|
||||
|
||||
echo "=== IPs Bloqueados ==="
|
||||
wc -l /etc/csf/csf.deny
|
||||
echo "Ultimos 5 bloqueios:"
|
||||
tail -5 /etc/csf/csf.deny
|
||||
|
||||
echo "=== LFD Status ==="
|
||||
systemctl is-active lfd
|
||||
|
||||
echo "=== Ataques Recentes (24h) ==="
|
||||
grep "$(date +%b\ %d)" /var/log/lfd.log 2>/dev/null | grep -c "blocked"
|
||||
```
|
||||
|
||||
**Thresholds:**
|
||||
- **OK:** CSF activo, LFD activo, <50 bloqueios/dia
|
||||
- **WARN:** >50 bloqueios/dia (possivel ataque)
|
||||
- **CRITICAL:** CSF/LFD inactivo
|
||||
|
||||
### Check 6: Email Security (server)
|
||||
|
||||
```bash
|
||||
# mcp__ssh-unified__ssh_execute(server="server")
|
||||
|
||||
# Executar script de verificacao (criado 12-03-2026)
|
||||
bash /root/scripts/email-security-check.sh 2>&1 | tail -20
|
||||
echo "Exit code: $?"
|
||||
# Exit 0 = OK, Exit 1 = erros detectados
|
||||
```
|
||||
|
||||
**Verifica:** Postfix header/body checks, content_filter (amavis), ClamAV, SpamAssassin, DMARC p=reject, Sieve anti-backscatter.
|
||||
|
||||
---
|
||||
|
||||
## Execucao Pratica
|
||||
|
||||
Agrupar comandos para minimizar chamadas SSH (3 chamadas total).
|
||||
|
||||
**Chamada 1 — server (SSL + portas + firewall):**
|
||||
```bash
|
||||
echo "=== SSL CERTS ===" && for dir in /root/.acme.sh/cwp_certs/*_ecc; do domain=$(basename "$dir" | sed 's/_ecc$//'); cert="$dir/${domain}.cer"; if [ -f "$cert" ]; then expiry=$(openssl x509 -enddate -noout -in "$cert" 2>/dev/null | cut -d= -f2); days=$(( ($(date -d "$expiry" +%s) - $(date +%s)) / 86400 )); if [ "$days" -lt 15 ]; then echo "CRITICAL ${days}d $domain"; elif [ "$days" -lt 30 ]; then echo "WARN ${days}d $domain"; else echo "OK ${days}d $domain"; fi; fi; done | sort && echo "=== PORTAS ===" && ss -tlnp | awk 'NR>1 {print $4}' | sed 's/.*://' | sort -n | uniq -c | sort -rn && echo "=== CSF ===" && csf -v && systemctl is-active lfd && wc -l /etc/csf/csf.deny && echo "Bloqueios hoje:" && grep "$(date +%b\ %d)" /var/log/lfd.log 2>/dev/null | grep -c "blocked"
|
||||
```
|
||||
|
||||
**Chamada 2 — server (backups + updates + email sec):**
|
||||
```bash
|
||||
echo "=== BACKUPS ===" && echo "MySQL daily:" && find /home/backup/mysql/daily/ -name "*.sql.gz" -mtime -2 2>/dev/null | wc -l && echo "Monthly:" && ls -lt /home/backup/monthly/ 2>/dev/null | head -3 && echo "=== UPDATES ===" && dnf check-update --quiet 2>/dev/null | grep -v "^$" | wc -l && dnf updateinfo list security 2>/dev/null | tail -5 && echo "=== EMAIL SEC ===" && bash /root/scripts/email-security-check.sh 2>&1 | tail -15 && echo "Exit: $?"
|
||||
```
|
||||
|
||||
**Chamada 3 — easy (updates + portas):**
|
||||
```bash
|
||||
echo "=== UPDATES ===" && apt list --upgradable 2>/dev/null | grep -v "^Listing" | wc -l && apt list --upgradable 2>/dev/null | grep -v "^Listing" | head -10 && echo "=== PORTAS ===" && ss -tlnp | grep LISTEN | wc -l && echo "=== DOCKER ===" && docker ps --format '{{.Names}}: {{.Status}}' 2>/dev/null | grep -i unhealthy && echo "=== DISCO ===" && df -h / /gordito 2>/dev/null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
```markdown
|
||||
## Security Check — [data via mcp-time]
|
||||
|
||||
### Resumo
|
||||
|
||||
| Servidor | SSL | Portas | Updates | Backups | Firewall | Email | Score |
|
||||
|----------|-----|--------|---------|---------|----------|-------|-------|
|
||||
| server | OK/WARN/CRIT | OK/WARN | OK/WARN/CRIT | OK/WARN/CRIT | OK/WARN/CRIT | OK/WARN | X/6 |
|
||||
| easy | n/a | OK/WARN | OK/WARN/CRIT | n/a | n/a | n/a | X/2 |
|
||||
|
||||
**Score global:** X/8 checks OK
|
||||
|
||||
### SSL Certificados ([N] dominios verificados)
|
||||
|
||||
| Estado | Dominio | Expira em | Data |
|
||||
|--------|---------|-----------|------|
|
||||
| CRITICAL | example.pt | Xd | YYYY-MM-DD |
|
||||
| WARN | example2.pt | Xd | YYYY-MM-DD |
|
||||
|
||||
[Se todos OK: "Todos os N certificados validos (minimo Xd)"]
|
||||
|
||||
### Portas Inesperadas
|
||||
| Porta | Processo | Accao Sugerida |
|
||||
|-------|----------|----------------|
|
||||
| XXXX | processo | Investigar / Fechar |
|
||||
|
||||
[Se nenhuma: "Todas as portas dentro do esperado"]
|
||||
|
||||
### Actualizacoes Pendentes
|
||||
- **server (CentOS):** N packages (M security)
|
||||
- **easy (Ubuntu):** N packages
|
||||
|
||||
### Backups
|
||||
- MySQL daily: N BDs com backup <48h [OK/WARN/CRIT]
|
||||
- Monthly: ultimo em DD-MM-YYYY [OK/WARN/CRIT]
|
||||
|
||||
### Firewall CSF
|
||||
- CSF: vXX [activo/inactivo]
|
||||
- LFD: [activo/inactivo]
|
||||
- IPs bloqueados: N permanentes
|
||||
- Bloqueios hoje: N
|
||||
|
||||
### Email Security
|
||||
- [resultado do script email-security-check.sh]
|
||||
|
||||
### Accoes Recomendadas
|
||||
1. [CRITICAL] Accao imediata
|
||||
2. [WARN] Accao recomendada
|
||||
3. [INFO] Melhorias opcionais
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scoring
|
||||
|
||||
| Score | Significado |
|
||||
|-------|-------------|
|
||||
| 8/8 | Excelente — tudo operacional |
|
||||
| 6-7/8 | Bom — warnings menores |
|
||||
| 4-5/8 | Atencao — accoes necessarias |
|
||||
| <4/8 | Critico — accao imediata |
|
||||
|
||||
**Calculo:** 1 ponto por cada check OK. WARN conta 0.5. CRITICAL conta 0.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```
|
||||
SSL CRITICAL (<15d):
|
||||
1. SSH server: /root/.acme.sh/acme.sh --renew -d DOMAIN --ecc
|
||||
2. Copiar para /etc/pki/tls/: /scripts/autossl_install_certs
|
||||
3. Reload nginx: /scripts/cwp_api webservers restart
|
||||
4. Verificar Cloudflare DNS-only (proxied impede Let's Encrypt)
|
||||
Ref: cwp-ssl-autorenew-fix.md
|
||||
|
||||
CSF/LFD inactivo:
|
||||
1. csf -e (activar)
|
||||
2. service lfd start
|
||||
3. Verificar /etc/csf/csf.conf (TESTING = "0")
|
||||
|
||||
Backup MySQL >72h:
|
||||
1. Verificar cron: crontab -l | grep backup
|
||||
2. Verificar espaco: df -h /home/backup/
|
||||
3. Verificar logs: /var/log/cron | grep backup
|
||||
|
||||
Muitos bloqueios CSF (>100/dia):
|
||||
1. Analisar origens: awk '{print $2}' /etc/csf/csf.deny | sort | uniq -c | sort -rn | head
|
||||
2. Se mesmo IP range: bloquear CIDR
|
||||
3. Se paises especificos: CC_DENY em csf.conf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integracao
|
||||
|
||||
- **/today** pode invocar `/security-check quick` como parte do checkup diario
|
||||
- **/infra-check** (cron) ja faz verificacao basica; `/security-check` e mais profundo e interactivo
|
||||
- **/server-health** cobre metricas de performance; `/security-check` foca-se em seguranca
|
||||
- **/cwp-security** foca-se em operacoes CSF; `/security-check` e auditoria abrangente
|
||||
- Resultado pode ser publicado na discussao #31 (Logs) do projecto #65
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- **Nunca** desactivar CSF para "resolver" problemas de acesso
|
||||
- **Nunca** ignorar certificado CRITICAL (<15d) — pode expirar antes do proximo check
|
||||
- **Nunca** actualizar kernel sem janela de manutencao planeada
|
||||
- **Sempre** verificar email-security apos alteracoes em Postfix/AMaViS
|
||||
- **Sempre** incluir timestamp via mcp-time no output
|
||||
|
||||
---
|
||||
|
||||
*Skill v1.0.0 | 12-03-2026 | Descomplicar*
|
||||
Reference in New Issue
Block a user