AgriFlow — Cosign: Firma y Verificación de Imágenes

Seguridad en la cadena de suministro de software · SOC 2 Compliance · Sigstore / Cosign v2

Keyless Signing SLSA Level 3 Kyverno Policy SOC 2 Ready

Pipeline de Seguridad — GitHub Actions → GKE Production

🏗️
docker build
Construir imagen
multiarch
📦
docker push
ghcr.io/
agriflow-io/
🔏
cosign sign
Firma keyless
OIDC GitHub
📋
SBOM + Attest
syft → spdx-json
cosign attest
🛡️
Vuln Scan
grype → json
cosign attest
📜
Rekor Log
Audit trail
inmutable
⚙️
Kyverno Admit
Bloquear si no
hay firma válida
📊
Estado de imágenes — Producción (agriflow-prod)
Último build: 2026-06-16 · Namespace: production · Cluster: gke-agriflow-prod-eu-west1
Servicio Digest (SHA256) Firmado SBOM Vuln Scan CVEs Críticos
agriflow-api
Node.js 22
sha256:4a8b2c... Firmado SBOM adjunto Escaneado 0
agriflow-ml
Python 3.12
sha256:9f3d7a... Firmado SBOM adjunto Escaneado 0
agriflow-worker
Node.js 22
sha256:c12e8b... Firmado SBOM adjunto Escaneado 2 Medium
agriflow-frontend
React / Nginx
sha256:7b5f1d... Firmado SBOM adjunto Escaneado 0
Todas las imágenes están firmadas — Kyverno está en modo Enforce; ningún pod no firmado puede entrar al namespace production.
⚙️
GitHub Actions — .github/workflows/build-sign.yml
Workflow reutilizable para todos los servicios de AgriFlow
📄 .github/workflows/build-sign.yml YAML
name: Build, Push & Sign Image

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: ghcr.io
  ORG: agriflow-io

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        service: [agriflow-api, agriflow-ml, agriflow-worker, agriflow-frontend]
    permissions:
      contents: read
      packages: write
      id-token: write    # Requerido para firma keyless Sigstore

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Login a GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build y Push imagen
        id: build
        run: |
          IMAGE=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service }}
          SHA_TAG=${IMAGE}:${{ github.sha }}
          docker build -t ${SHA_TAG} ./services/${{ matrix.service }}
          docker push ${SHA_TAG}
          # Exportar digest para usarlo en firma
          DIGEST=$(docker inspect --format '{{index .RepoDigests 0}}' ${SHA_TAG})
          echo "digest=${DIGEST}" >> $GITHUB_OUTPUT

      - name: Instalar Cosign
        uses: sigstore/cosign-installer@v3

      - name: Firmar imagen (keyless)
        run: |
          cosign sign --yes ${{ steps.build.outputs.digest }}
        env:
          COSIGN_EXPERIMENTAL: "1"

      - name: Instalar syft (SBOM)
        uses: anchore/sbom-action/download-syft@v0

      - name: Generar y adjuntar SBOM
        run: |
          syft ${{ steps.build.outputs.digest }} -o spdx-json > sbom.spdx.json
          cosign attest --yes \
            --predicate sbom.spdx.json \
            --type spdxjson \
            ${{ steps.build.outputs.digest }}

      - name: Escanear vulnerabilidades (grype)
        uses: anchore/scan-action@v4
        with:
          image: ${{ steps.build.outputs.digest }}
          output-format: json
          fail-build: false

      - name: Adjuntar resultados de escaneo
        run: |
          cosign attest --yes \
            --predicate results.json \
            --type vuln \
            ${{ steps.build.outputs.digest }}
🔍
Verificación Manual — CLI de referencia
Comandos para verificar firmas y attestations desde terminal
🖥️ Terminal — Verificar firma y attestations Bash
# ── Verificar firma de imagen ────────────────────────────────────
cosign verify \
  --certificate-identity-regexp="https://github.com/agriflow-io/.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/agriflow-io/agriflow-api@sha256:4a8b2c...

# Salida esperada:
Verification for ghcr.io/agriflow-io/agriflow-api@sha256:4a8b2c --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - Existence of the claims in the transparency log was verified offline
  - The code-signing certificate claims were validated

# ── Verificar y ver SBOM adjunto ────────────────────────────────
cosign verify-attestation \
  --type spdxjson \
  --certificate-identity-regexp="https://github.com/agriflow-io/.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/agriflow-io/agriflow-api@sha256:4a8b2c... \
  | jq '.payload' | base64 -d | jq '.'

# ── Ver resultados de vulnerabilidades ───────────────────────────
cosign verify-attestation \
  --type vuln \
  --certificate-identity-regexp="https://github.com/agriflow-io/.*" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  ghcr.io/agriflow-io/agriflow-api@sha256:4a8b2c... \
  | jq '.payload' | base64 -d | jq '.predicate.scanner.result.matches[] | {severity, package: .artifact.name}'

# ── Buscar en el Rekor transparency log ──────────────────────────
rekor-cli search --sha sha256:4a8b2c...
Política Kyverno — Admission Controller
Bloqueo de imágenes sin firma válida en namespace production
⚠️
validationFailureAction: Enforce — Esta política bloquea cualquier Pod que intente usar una imagen de ghcr.io/agriflow-io/* sin firma válida de GitHub Actions.
☸️ k8s/policies/verify-image-signatures.yaml YAML
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-agriflow-signatures
  annotations:
    policies.kyverno.io/title: Verify AgriFlow Image Signatures
    policies.kyverno.io/description: |
      Verifica que todas las imágenes de ghcr.io/agriflow-io/* estén
      firmadas por GitHub Actions usando Sigstore keyless signing.
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: verify-cosign-keyless
      match:
        any:
          - resources:
              kinds: ["Pod"]
              namespaces: ["production"]
      verifyImages:
        - imageReferences:
            - "ghcr.io/agriflow-io/*"
          mutateDigest: true      # Mutar tag → digest (inmutable)
          verifyDigest: true
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/agriflow-io/*"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: "https://rekor.sigstore.dev"
          attestations:
            - predicateType: "https://spdx.dev/Document"
              attestors:
                - entries:
                    - keyless:
                        subject: "https://github.com/agriflow-io/*"
                        issuer: "https://token.actions.githubusercontent.com"

---
# Aplicar política:
# kubectl apply -f k8s/policies/verify-image-signatures.yaml
# kubectl get clusterpolicy verify-agriflow-signatures
📋
SBOM de ejemplo — agriflow-api:main@sha256:4a8b2c
Fragmento SPDX-JSON generado por syft y adjuntado como attestation
📄 sbom.spdx.json (fragmento) JSON
{
  "spdxVersion": "SPDX-2.3",
  "dataLicense": "CC0-1.0",
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "agriflow-api-4a8b2c",
  "documentNamespace": "https://github.com/agriflow-io/agriflow-api/sbom-4a8b2c",
  "creationInfo": {
    "created": "2026-06-16T09:14:32Z",
    "creators": ["Tool: syft-1.3.0", "Organization: agriflow-io"]
  },
  "packages": [
    {
      "SPDXID": "SPDXRef-express-4.18.2",
      "name": "express",
      "versionInfo": "4.18.2",
      "licenseConcluded": "MIT",
      "downloadLocation": "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
    },
    /* ... 247 paquetes más */
  ]
}
📏
Buenas Prácticas — Checklist SOC 2
8 reglas de seguridad de cadena de suministro para AgriFlow
  • 1
    Firma keyless en CI

    Usar Sigstore keyless en GitHub Actions. Sin gestión de claves, las firmas están ligadas a la identidad OIDC del workflow. Se usa id-token: write y se registra en Rekor.

  • 2
    Firmar todas las imágenes

    Firmar en CI/CD y verificar antes del despliegue. Ninguna imagen sin firma puede llegar a production.

  • 3
    SBOM en cada build

    Generar y adjuntar SBOM con syft en cada build. Requerido para cumplimiento (Executive Order 14028) y seguimiento de vulnerabilidades.

  • 4
    Verificar en admission control

    Usar Kyverno para verificar firmas en el Kubernetes admission level. La política está en modo Enforce, no solo Audit.

  • 5
    Rekor transparency log

    Las firmas keyless se registran en Rekor. Proporciona un audit trail inmutable de quién firmó qué y cuándo — clave para SOC 2.

  • 6
    Attestations de proveniencia SLSA

    Adjuntar attestations SLSA que prueban dónde y cómo se construyó cada imagen. Objetivo: SLSA Level 3 para AgriFlow.

  • 7
    Referenciar por digest, no por tag

    Usar image@sha256:... en lugar de image:latest. Los tags pueden sobreescribirse; los digests son inmutables. Kyverno muta automáticamente.

  • 8
    Adjuntar resultados de vulnerability scan

    Adjuntar resultados de grype como attestations. Verificar ausencia de CVEs críticos antes de aprobar despliegue en producción.

🔑
Sin gestión de claves
Keyless signing elimina el riesgo de robo o pérdida de claves privadas. La identidad es el workflow de GitHub Actions.
📜
Audit trail Rekor
Cada firma queda registrada en el transparency log público de Sigstore. Inmutable y verificable por terceros.
Zero-trust deployment
Kyverno bloquea cualquier imagen no firmada. Si el pipeline falla antes de firmar, el pod no se crea en producción.
📊
SLSA Level 3
Con provenance attestations + SBOM + firma keyless, AgriFlow alcanza SLSA Level 3, preparado para auditoría SOC 2.