Files
apps-registry/docs/devsecops/cosign.md
T
devopsandClaude Sonnet 5 ac095ff981
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 58s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 32s
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 35s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 18m58s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 12m0s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 5m43s
fix(devsecops): firmar y verificar imagenes por digest, no por tag
Los 3 pipelines (frontend, commerce-backend, docs-portal) ahora capturan
el digest real del docker push y lo usan como referencia para cosign
sign/verify, en vez del tag mutable :VERSION. Documenta ademas la
decision de mantener Rekor deshabilitado (registry privado, evita
dependencia de red saliente hacia rekor.sigstore.dev via el tunel).

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

48 lines
2.4 KiB
Markdown

# Firma de imágenes con Cosign
Los 3 pipelines que construyen y publican imágenes hacia `gitea.cruzcloud.net`
(frontend en `.gitea/workflows/build.yaml`, commerce-backend en
`build-medusa.yaml`, docs-portal en `deploy-docs.yaml`) firman la imagen con
Cosign (par de llaves propio, sin CA externa) inmediatamente después del
`docker push` y antes de que cualquier manifiesto pueda referenciarla.
## Firma por digest, no por tag
Desde 2026-08-16 los tres workflows firman y verifican por **digest**
(`${IMAGE_NAME}@sha256:...`), no por tag (`${IMAGE_NAME}:${VERSION}`).
Motivo: `:VERSION` y `:latest` son punteros mutables — nada impide que en el
futuro un tag se vuelva a mover a otro contenido. El digest identifica el
contenido exacto de la imagen que Trivy ya escaneó unos pasos antes en el
mismo job, así que la firma queda atada a ese contenido específico, no al
nombre que apunta a él en un momento dado.
El digest se captura parseando la salida de `docker push` (`sha256:[a-f0-9]{64}`)
inmediatamente después de subir la imagen, y se pasa como `steps.push.outputs.digest`
a los pasos de firma y verificación (smoke test) que corren a continuación en
el mismo job.
## Rekor / transparency log: deshabilitado (decisión, no pendiente)
`cosign sign` corre con `--use-signing-config=false --tlog-upload=false` en
los tres workflows — evaluado y confirmado el 2026-08-16, se mantiene así.
Razones:
- El registry (`gitea.cruzcloud.net`) es privado, de un lab. No hay valor de
auditoría en anunciar públicamente en Rekor qué se firmó y cuándo.
- Subir al transparency log público requiere una llamada de red saliente por
build hacia `rekor.sigstore.dev`, atravesando el túnel de Cloudflare. Este
túnel ya tuvo un incidente de SNI/orden con Cosign (ver memoria de
infraestructura), así que sumar otra dependencia de red saliente por cada
build agrega superficie de fallo sin beneficio real en este contexto.
- Impacto en tiempo de pipeline: evitado por completo al no hacer la llamada.
Si el registry deja de ser privado, o aparece un requisito de compliance
externo que exija prueba pública de firma, revisar esta decisión.
## Llaves públicas
Cada app commitea su llave pública junto al resto de sus manifiestos
(`workloads/<app>/cosign.pub`), para que la verificación (paso de smoke test
dentro del mismo workflow) sea local y no dependa de un servicio externo.