Files
apps-registry/workloads/docs-portal/docs/devsecops/index.md
T
devopsandClaude Sonnet 5 b0b832f142
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 36s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m18s
docs(docs-portal): reflejar fixes de MTU, gitea-runner y cosign digest/rekor
Nuevo playbook del blackhole MTU cross-node (diagnostico + fix + validacion).
Actualiza el playbook de contencion de recursos Gitea/runner de 'pendiente'
a 'aplicado'. Actualiza cosign.md: firma por digest ya implementada, Rekor
como decision tomada (no TODO). Corrige 2 links que quedaron rotos al
renombrar la seccion de limitaciones (validado con mkdocs build --strict).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011FqYP3Wf1W63Qmh7qgXAAT
2026-08-16 23:07:26 -05:00

117 lines
6.3 KiB
Markdown

# DevSecOps
Fase 2 del lab: integrar tooling de seguridad al pipeline de Gitea
Actions. Se empezó por un solo repo de referencia — el frontend de ARI
Shopping (`workloads/ecommerce`, `.gitea/workflows/build.yaml`) — y ya
está replicado, con evidencia real de corridas en verde, a los tres
componentes del monorepo:
| App | Workflow | Imagen | Adaptación de Semgrep |
|---|---|---|---|
| Frontend (Next.js) | `build.yaml` | `ecommerce-frontend` | `p/typescript` + `p/react` + `p/nextjs` + `p/security-audit` |
| Backend (Medusa v2, API TypeScript) | `build-medusa.yaml` | `ecommerce-medusa` | `p/typescript` + `p/security-audit` + `p/owasp-top-ten` (sin React/Next.js — es una API, no SSR) |
| Docs Portal (MkDocs, Python) | `deploy-docs.yaml` | `docs-portal` | `p/python` + `p/security-audit` (sin código de aplicación propio hoy) |
Cada app tiene su propia llave pública de Cosign commiteada
(`cosign.pub` en su propio directorio), pero las tres comparten el
mismo par de llaves de firma (mismos secrets `COSIGN_PRIVATE_KEY` /
`COSIGN_PASSWORD` a nivel de repo) — una sola identidad de firma para
todo el registry de este lab.
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
El mismo patrón corre, con el mismo orden de etapas, en los tres
workflows (`build.yaml`, `build-medusa.yaml`, `deploy-docs.yaml`) — lo
que cambia entre ellos es el ruleset de Semgrep y qué manifiesto(s)
escanea Trivy IaC (ver tabla arriba), no la estructura del pipeline.
```mermaid
flowchart TD
subgraph J1["job: gitleaks (push + pull_request)"]
A1[checkout] --> A2["gitleaks detect --no-git"]
end
A2 -- "secreto encontrado" --> XA["❌ pipeline detenido<br/>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<br/>(manifiesto K8s de la app)"]
B1 -.informa.-> B2["Semgrep SAST<br/>(ruleset por stack, audit mode)"]
B2 -.informa.-> B3[login registry]
B3 --> B4["docker build<br/>(push: false, load: true)"]
B4 --> B5["Trivy imagen<br/>CRITICAL"]
B5 -- "CRITICAL con fix" --> XB["❌ detenido<br/>no se sube la imagen"]
B5 -- "sin CRITICAL" --> B6["Trivy imagen<br/>HIGH (informa)"]
B6 --> B7["Syft → SBOM<br/>(CycloneDX + SPDX)"]
B7 --> B8["docker push"]
B8 --> B9["cosign sign"]
B9 --> B10["cosign verify<br/>(smoke test)"]
B10 -- "firma inválida" --> XC["❌ detenido"]
B10 -- "firma válida" --> B11["actualizar manifiesto de la app<br/>(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.
- `commerce-backend` tiene dos CVE CRITICAL documentados como excepción
puntual en `workloads/commerce-backend/.trivyignore` (Go stdlib
embebido en el binario de esbuild, sin fix compatible con la versión
de Vite que usa el admin-sdk de Medusa hoy) — revisar en cada bump de
`@medusajs/*` si ya deja de ser necesaria.
- Contención de recursos entre Gitea y su runner bajo carga real —
causa raíz confirmada, fix propuesto y documentado, aplicación
manual pendiente (ver
[playbook de contención de recursos](../playbooks/incidente-contencion-recursos-gitea-runner-2026-08.md)).