diff --git a/workloads/docs-portal/docs/devsecops/index.md b/workloads/docs-portal/docs/devsecops/index.md new file mode 100644 index 0000000..23d5761 --- /dev/null +++ b/workloads/docs-portal/docs/devsecops/index.md @@ -0,0 +1,91 @@ +# DevSecOps + +Fase 2 del lab: integrar tooling de seguridad al pipeline de Gitea +Actions, empezando por un solo repo de referencia — el frontend de ARI +Shopping (`workloads/ecommerce`, `.gitea/workflows/build.yaml`) — antes +de replicarlo a `commerce-backend` y `docs-portal`. + +Cinco herramientas, cada una respondiendo una pregunta distinta: + +| Herramienta | Pregunta que responde | Modo | +|---|---|---| +| [Gitleaks](gitleaks.md) | ¿Hay un secreto commiteado? | **Bloquea** | +| [Trivy — imagen](trivy.md) | ¿La imagen tiene una CVE conocida? | CRITICAL **bloquea**, HIGH informa | +| [Trivy — IaC](trivy.md) | ¿El manifiesto de Kubernetes es inseguro? | Informa | +| [Semgrep (SAST)](sast.md) | ¿El código tiene un patrón inseguro conocido? | Informa (auditoría) | +| [Syft (SBOM)](sbom.md) | ¿Qué paquetes exactos quedaron en la imagen? | Informa (inventario) | +| [Cosign](cosign.md) | ¿Esta imagen es exactamente la que armó el pipeline? | **Bloquea** (smoke test) | + +## El pipeline completo + +```mermaid +flowchart TD + subgraph J1["job: gitleaks (push + pull_request)"] + A1[checkout] --> A2["gitleaks detect --no-git"] + end + + A2 -- "secreto encontrado" --> XA["❌ pipeline detenido
build nunca arranca"] + A2 -- "limpio" --> B0 + + subgraph J2["job: build (solo push a main, needs: gitleaks)"] + B0[checkout + validaciones de código] --> B1["Trivy IaC
(frontend.yaml)"] + B1 -.informa.-> B2["Semgrep SAST
(audit mode)"] + B2 -.informa.-> B3[login registry] + B3 --> B4["docker build
(push: false, load: true)"] + B4 --> B5["Trivy imagen
CRITICAL"] + B5 -- "CRITICAL con fix" --> XB["❌ detenido
no se sube la imagen"] + B5 -- "sin CRITICAL" --> B6["Trivy imagen
HIGH (informa)"] + B6 --> B7["Syft → SBOM
(CycloneDX + SPDX)"] + B7 --> B8["docker push"] + B8 --> B9["cosign sign"] + B9 --> B10["cosign verify
(smoke test)"] + B10 -- "firma inválida" --> XC["❌ detenido"] + B10 -- "firma válida" --> B11["actualizar frontend.yaml
(GitOps, Argo CD sincroniza)"] + end +``` + +## Por qué este orden + +- **Gitleaks corre en un job aparte, antes que todo lo demás** — incluso + antes que el checkout completo del job de build. Si hay un secreto, + no tiene sentido gastar minutos de build en un commit que hay que + rechazar igual. Es el único check que corre también en `pull_request`, + no solo en push a `main`. +- **Trivy IaC y Semgrep corren antes del build de Docker.** Ninguno de + los dos necesita la imagen construida — analizan manifiestos y código + fuente respectivamente — así que si algo llamativo apareciera ahí, se + sabe temprano, sin esperar el build (que es el paso más lento del + pipeline). +- **Trivy imagen corre después del build pero antes del push.** Por eso + el build usa `push: false, load: true`: la imagen queda en el daemon + local del runner, escaneable, pero no sale hacia el registry hasta + pasar el gate de CRITICAL. +- **Syft (SBOM) corre sobre la imagen ya validada**, antes del push — + documenta exactamente lo que se está por publicar. +- **Cosign firma después del push exitoso** (no tiene sentido firmar + algo que no llegó al registry) y se verifica en el mismo pipeline como + smoke test. + +## Qué pasa si cada uno falla + +| Si falla... | El pipeline... | +|---|---| +| Gitleaks | Se detiene ahí mismo. El job `build` nunca arranca (`needs: gitleaks`). Nada se construye. | +| Trivy IaC | No se detiene — el hallazgo queda en el log, informativo. | +| Semgrep | No se detiene — mismo criterio: primera vuelta en modo auditoría. | +| Trivy imagen (CRITICAL) | Se detiene después del build, antes del push. La imagen con la CVE nunca llega al registry. | +| Trivy imagen (HIGH) | No se detiene — se reporta para revisar en conjunto. | +| Syft | Si el propio comando falla (no si "encuentra algo" — un SBOM no tiene hallazgos que bloqueen), el pipeline se detiene por error real de la herramienta. | +| Cosign sign/verify | Se detiene. Si la imagen se firmó pero no verifica, algo está mal con las llaves o con la imagen — no se continúa con la promoción GitOps. | + +## Qué falta después de esta primera vuelta + +- Revisar en conjunto los hallazgos de Trivy IaC y Semgrep (hoy + informativos) y decidir cuáles pasan a bloquear. +- Decidir si Trivy imagen sube el umbral de bloqueo a HIGH una vez que + el backlog de CVEs conocidas esté bajo control. +- Admission controller en el cluster que verifique la firma de Cosign + antes de dejar correr un Pod (ver [cosign.md](cosign.md)) — hoy la + verificación es solo un smoke test dentro del propio pipeline. +- Replicar este mismo patrón a `commerce-backend` (Medusa) y + `docs-portal`, adaptando lo que corresponda a cada stack. diff --git a/workloads/docs-portal/mkdocs.yml b/workloads/docs-portal/mkdocs.yml index 5dd51ed..dbcc013 100644 --- a/workloads/docs-portal/mkdocs.yml +++ b/workloads/docs-portal/mkdocs.yml @@ -99,6 +99,7 @@ nav: - Inicio: guia-estudiante/README.md - Conceptos básicos: guia-estudiante/conceptos-basicos.md - DevSecOps: + - Resumen: devsecops/index.md - Gitleaks (secretos): devsecops/gitleaks.md - Trivy (imagen + IaC): devsecops/trivy.md - SAST (Semgrep): devsecops/sast.md