<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sbom on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/sbom/</link><description>Recent content in Sbom on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Sun, 26 Jul 2026 18:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/sbom/index.xml" rel="self" type="application/rss+xml"/><item><title>Cadena de confianza del modelo (3/4): firma, procedencia y AIBOM — por qué te fías de esos bytes</title><link>https://blog.lo0.es/posts/firma-procedencia-aibom-cadena-suministro-modelo/</link><pubDate>Sun, 26 Jul 2026 18:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/firma-procedencia-aibom-cadena-suministro-modelo/</guid><description>&lt;p>En el &lt;a href="https://blog.lo0.es/posts/kserve-open-inference-protocol-plano-control/">primer artículo&lt;/a> de esta serie montamos el plano de control del serving; en el &lt;a href="https://blog.lo0.es/posts/registro-distribucion-modelos-oci-oras/">segundo&lt;/a>, de dónde salen los bytes. Al final de ese recorrido hay un &lt;code>initContainer&lt;/code> que hace &lt;code>oras pull&lt;/code> de un artefacto de 140 GB y lo deja en un volumen del que vLLM va a leer. La pregunta incómoda es la que da título a este tercero: &lt;strong>¿por qué te fías de esos bytes?&lt;/strong>&lt;/p>
&lt;p>La respuesta habitual —&amp;ldquo;porque vienen de nuestro registro&amp;rdquo;— es la que la disciplina de cadena de suministro lleva una década desmontando: un registro es un almacén, no una autoridad; guarda lo que le suben, y quien puede subir puede envenenar. Aquí cubrimos las cuatro piezas que convierten esa frase en algo que una máquina verifica antes de que arranque el pod —&lt;strong>firma&lt;/strong> (Sigstore), &lt;strong>firma de modelos&lt;/strong> (OpenSSF Model Signing), &lt;strong>procedencia&lt;/strong> (SLSA e in-toto) e &lt;strong>inventario de materiales&lt;/strong> (AIBOM)— y la parte que casi nunca se cuenta: qué demuestra de verdad cada una.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;ul>
&lt;li>El artefacto de modelo es &lt;strong>código de terceros con acceso a tus datos&lt;/strong>. &lt;code>pickle&lt;/code> ejecuta código en &lt;code>torch.load&lt;/code>; safetensors elimina esa clase de ataque pero &lt;strong>no dice nada sobre si los pesos están envenenados&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Sigstore&lt;/strong> es la pieza madura: &lt;code>cosign&lt;/code> 3.1.1 (9 de junio de 2026), Rekor v2 en GA desde el 10 de octubre de 2025. En air-gap, PKI propia o Sigstore privado; el bundle nuevo permite verificar &lt;strong>offline&lt;/strong>.&lt;/li>
&lt;li>Un modelo &lt;strong>no es un fichero&lt;/strong>. &lt;strong>OpenSSF Model Signing (OMS)&lt;/strong> v1 (junio de 2025) firma un &lt;strong>manifiesto de hashes&lt;/strong> de todo el directorio; la librería de referencia, &lt;code>model_signing&lt;/code> 1.1.1, está en &lt;em>sandbox&lt;/em> de OpenSSF.&lt;/li>
&lt;li>&lt;strong>SLSA v1.2&lt;/strong> (24 de noviembre de 2025) añade el &lt;em>Source track&lt;/em>; &lt;strong>Build L3&lt;/strong> es el objetivo realista en fine-tuning. &lt;strong>in-toto&lt;/strong> graduó en la CNCF el 23 de abril de 2025.&lt;/li>
&lt;li>&lt;strong>AIBOM&lt;/strong>: SPDX 3.0.1 y CycloneDX 1.7 (ECMA-424 2ª ed.) tienen los campos; el tooling que los rellena automáticamente casi no existe. Se emite desde el pipeline, no desde un escáner.&lt;/li>
&lt;li>&lt;strong>Regulación&lt;/strong>: el art. 53 del AI Act obliga a proveedores de GPAI desde el 2 de agosto de 2025, y el Reglamento (UE) 2026/1744 retrasó el alto riesgo a diciembre de 2027 y agosto de 2028 &lt;strong>sin tocar GPAI&lt;/strong>. La CRA exige SBOM —no AIBOM— con aplicación plena el 11 de diciembre de 2027.&lt;/li>
&lt;li>&lt;strong>Nada de esto dice que el modelo sea bueno.&lt;/strong> Ultralytics produjo atestaciones válidas de artefactos con un criptominero dentro.&lt;/li>
&lt;/ul>
&lt;h2 id="la-analogía-la-trazabilidad-del-lote">La analogía: la trazabilidad del lote&lt;/h2>
&lt;p>Un lote de jamón que llega al muelle de un supermercado trae cuatro cosas que es fácil confundir. Un &lt;strong>número de lote&lt;/strong>, que lo identifica y a ningún otro: el &lt;code>sha256&lt;/code>. Un &lt;strong>precinto&lt;/strong> del matadero, que si está roto delata manipulación en el transporte: la firma. Un &lt;strong>registro sanitario&lt;/strong> que dice de qué matadero salió, en qué fecha y bajo qué inspección: la atestación de procedencia. Y una &lt;strong>etiqueta de ingredientes y alérgenos&lt;/strong>: el AIBOM. En el muelle, el encargado no acepta el palé si el precinto está roto o falta el registro: eso es el admission control.&lt;/p>
&lt;p>La analogía se sostiene hasta el detalle: el precinto viaja pegado por fuera, no dentro del jamón (es una firma separada); el registro lo emite el matadero, no el transportista, y su valor depende de que la inspección sea real; y lo que permite retirar producto cuando aparece un problema es el número de lote, no el precinto.&lt;/p>
&lt;p>Pero sirve sobre todo por lo que &lt;strong>no&lt;/strong> promete: &lt;strong>un jamón perfectamente trazado, precintado y etiquetado puede estar en mal estado&lt;/strong>. La trazabilidad responde a &amp;ldquo;de dónde vino y si alguien lo tocó&amp;rdquo;; no responde a &amp;ldquo;está bueno&amp;rdquo;. Este artículo trata de la primera pregunta; la segunda es trabajo de &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">evaluación&lt;/a> y de &lt;a href="https://blog.lo0.es/posts/guardrails-safety-llm/">guardrails&lt;/a>, y confundirlas es el error más caro de esta disciplina.&lt;/p>
&lt;div class="diagram" style="max-width:820px;margin:1.5rem auto;">
&lt;svg viewBox="0 0 820 280" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Cadena de custodia del artefacto de modelo: pipeline de entrenamiento, sellado con firma y atestaciones, registro OCI, verificación en admission y carga en GPU">
&lt;rect x="14" y="70" width="140" height="86" rx="10" fill="none" stroke="currentColor" stroke-width="1.6"/>
&lt;text x="84" y="100" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="700" fill="currentColor">Pipeline&lt;/text>
&lt;text x="84" y="118" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">QLoRA / merge&lt;/text>
&lt;text x="84" y="134" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">runner efímero&lt;/text>
&lt;rect x="184" y="52" width="150" height="122" rx="10" fill="none" stroke="currentColor" stroke-width="1.6"/>
&lt;text x="259" y="78" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="700" fill="currentColor">Sellado&lt;/text>
&lt;text x="259" y="98" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">manifiesto de hashes&lt;/text>
&lt;text x="259" y="114" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">firma (OMS / cosign)&lt;/text>
&lt;text x="259" y="130" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">provenance SLSA&lt;/text>
&lt;text x="259" y="146" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">AIBOM&lt;/text>
&lt;rect x="364" y="70" width="140" height="86" rx="10" fill="none" stroke="currentColor" stroke-width="1.6"/>
&lt;text x="434" y="100" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="700" fill="currentColor">Registro OCI&lt;/text>
&lt;text x="434" y="118" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">artefacto + referrers&lt;/text>
&lt;text x="434" y="134" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">inmutable por digest&lt;/text>
&lt;rect x="534" y="52" width="146" height="122" rx="10" fill="none" stroke="currentColor" stroke-width="1.6"/>
&lt;text x="607" y="78" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="700" fill="currentColor">Muelle&lt;/text>
&lt;text x="607" y="98" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">admission control&lt;/text>
&lt;text x="607" y="114" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">verifica firma&lt;/text>
&lt;text x="607" y="130" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">exige provenance&lt;/text>
&lt;text x="607" y="146" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">fail-closed&lt;/text>
&lt;rect x="710" y="70" width="96" height="86" rx="10" fill="none" stroke="currentColor" stroke-width="1.6"/>
&lt;text x="758" y="100" text-anchor="middle" font-family="sans-serif" font-size="12" font-weight="700" fill="currentColor">GPU&lt;/text>
&lt;text x="758" y="118" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">re-verifica&lt;/text>
&lt;text x="758" y="134" text-anchor="middle" font-family="sans-serif" font-size="10.5" fill="currentColor">antes de cargar&lt;/text>
&lt;path d="M154,113 L182,113" stroke="currentColor" stroke-width="1.6" fill="none"/>
&lt;path d="M334,113 L362,113" stroke="currentColor" stroke-width="1.6" fill="none"/>
&lt;path d="M504,113 L532,113" stroke="currentColor" stroke-width="1.6" fill="none"/>
&lt;path d="M680,113 L708,113" stroke="currentColor" stroke-width="1.6" fill="none"/>
&lt;text x="410" y="222" text-anchor="middle" font-family="sans-serif" font-size="11" fill="currentColor">El precinto se pone una vez, en el origen; se comprueba dos veces: en el muelle y antes de cargar.&lt;/text>
&lt;text x="410" y="252" text-anchor="middle" font-family="sans-serif" font-size="10.5" font-style="italic" fill="currentColor">La trazabilidad no dice que el modelo sea bueno. Dice de dónde vino y si alguien lo tocó.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;h2 id="el-modelo-de-amenaza-sin-generalidades">El modelo de amenaza, sin generalidades&lt;/h2>
&lt;h3 id="pickle-y-qué-resuelve-safetensors">&lt;code>pickle&lt;/code>, y qué resuelve safetensors&lt;/h3>
&lt;p>El problema de &lt;code>pickle&lt;/code> no es un bug, es su semántica: un objeto puede definir &lt;code>__reduce__&lt;/code> y al deserializar Python &lt;strong>ejecuta&lt;/strong> lo que ese método devuelva. Un checkpoint de &lt;code>torch.save&lt;/code> no es un contenedor de números; es un programa que al cargarse puede abrir un shell inverso. No es teórico: en febrero de 2024 JFrog documentó alrededor de &lt;strong>cien modelos maliciosos&lt;/strong> en Hugging Face con payload real —PyTorch con &lt;code>__reduce__&lt;/code> inyectado, Keras abusando de la capa &lt;code>Lambda&lt;/code>—, y en febrero de 2025 ReversingLabs describió &lt;strong>nullifAI&lt;/strong>, dos modelos con ficheros pickle deliberadamente corruptos que evadían a Picklescan aprovechando que el payload se ejecuta &lt;em>antes&lt;/em> de que el fichero falle. La respuesta llegó tarde: &lt;strong>PyTorch 2.6 invirtió el valor por defecto de &lt;code>weights_only&lt;/code> a &lt;code>True&lt;/code>&lt;/strong>, restringiendo la deserialización a una lista blanca de tipos. Rompió mucho código —hay issues abiertos en &lt;code>nnUNet&lt;/code>, &lt;code>accelerate&lt;/code> y media docena de proyectos más— y no es garantía formal: esa lista blanca ha tenido escapes documentados.&lt;/p>
&lt;p>&lt;code>safetensors&lt;/code> sí resuelve la clase entera: datos puros —cabecera JSON con offsets más un blob de tensores—, sin ejecución posible. La auditoría de Trail of Bits para EleutherAI y Hugging Face, del 23 de mayo de 2023, &lt;strong>no encontró ningún fallo crítico que llevara a ejecución arbitraria de código&lt;/strong>, y de propina el mapeo directo a memoria da cargas del orden de cien veces más rápidas en CPU, algo que ya explotamos en &lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">la ruta del disco a la HBM&lt;/a>.&lt;/p>
&lt;p>El matiz que se olvida sistemáticamente: &lt;strong>safetensors garantiza que cargar el fichero no ejecuta código; no garantiza nada sobre los números que hay dentro&lt;/strong>. Un modelo con puerta trasera entrenada —normal salvo ante un disparador concreto— se distribuye en safetensors, pasa los escáneres y firma sin problema. Es el jamón precintado que está malo.&lt;/p>
&lt;h3 id="adapters-lora-tags-mutables-y-el-modelo-del-viernes">Adapters LoRA, tags mutables y el modelo del viernes&lt;/h3>
&lt;p>Un adapter pesa megabytes, se comparte con ligereza y en un stack de &lt;a href="https://blog.lo0.es/posts/multi-lora-serving-fundamentos/">multi-LoRA&lt;/a> se cargan decenas en caliente sobre el mismo base: es el vector más barato para el atacante y el que menos gobierno tiene. La literatura de 2026 es densa en detección —arXiv 2602.15195, revisado en abril de 2026, reporta &lt;strong>ROC-AUC de 1,00&lt;/strong> clasificando adapters por estadísticos espectrales de las proyecciones de atención—, pero con la cabeza fría son adapters envenenados por los propios autores con un método conocido: investigación viva, no defensa desplegable. La respuesta operativa realista sigue siendo &lt;strong>de dónde vino el adapter y quién lo firmó&lt;/strong>.&lt;/p>
&lt;p>Y dos amenazas sin atacante. Un tag es mutable: &lt;code>mi-registro/llama-70b:produccion&lt;/code> puede apuntar hoy a un digest y mañana a otro sin que cambie una línea de tus manifiestos, y basta un &lt;code>oras push&lt;/code> bienintencionado; mitigación idéntica a la de las imágenes en el &lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">hardening del stack&lt;/a>, &lt;strong>fijar por digest, nunca por tag&lt;/strong>, con el detalle de que el digest es lo que la firma cubre. Y el clásico: un ingeniero convierte un checkpoint en su portátil, hace &lt;code>oras push&lt;/code> con sus credenciales y el lunes hay un &lt;code>InferenceService&lt;/code> sirviéndolo, sin firma, procedencia ni AIBOM. &lt;strong>No es malicioso; es ingobernable.&lt;/strong> Aquí la firma rinde no porque detecte un ataque, sino porque &lt;strong>hace inviable el atajo&lt;/strong>.&lt;/p>
&lt;h3 id="ultralytics-firma-válida-artefacto-envenenado">Ultralytics: firma válida, artefacto envenenado&lt;/h3>
&lt;p>El 4 y 5 de diciembre de 2024, las versiones 8.3.41 y 8.3.42 de &lt;code>ultralytics&lt;/code> (YOLO) se publicaron en PyPI con un criptominero, por &lt;strong>envenenamiento de la caché de GitHub Actions&lt;/strong> en el workflow de publicación; días después llegó una segunda ronda (8.3.45 y 8.3.46) con tokens de API no rotados al migrar a &lt;em>Trusted Publishing&lt;/em>. El detalle que importa: &lt;strong>las cuatro versiones maliciosas llevaban atestaciones válidas&lt;/strong>, porque las generó el propio workflow. La firma era correcta y la procedencia también; lo comprometido era el entorno de build. Como resumió el investigador que lo destapó, una atestación garantiza la relación entre un artefacto y un job de build más un commit — no entre las intenciones del desarrollador y el artefacto final.&lt;/p>
&lt;h2 id="sigstore-quién-firmó-y-cómo-lo-compruebas-sin-llamar-a-nadie">Sigstore: quién firmó, y cómo lo compruebas sin llamar a nadie&lt;/h2>
&lt;p>Sigstore son tres piezas y un cliente. &lt;strong>Fulcio&lt;/strong> es una CA que, a cambio de un token OIDC válido, emite un certificado X.509 de vida muy corta ligado a esa identidad. &lt;strong>Rekor&lt;/strong> es un log de transparencia de solo-anexado donde queda constancia de la firma con su sello temporal. &lt;strong>cosign&lt;/strong> lo orquesta. El resultado es la &lt;strong>firma keyless&lt;/strong>: no hay clave privada de larga duración que custodiar, hay una identidad OIDC —el workflow de CI— y un registro inmutable de que esa identidad firmó ese digest.&lt;/p>
&lt;p>Estado a julio de 2026: &lt;strong>cosign 3.1.1&lt;/strong>, del 9 de junio de 2026. La rama 3.x, desde el 8 de octubre de 2025, activó &lt;strong>por defecto&lt;/strong> el formato de bundle nuevo, &lt;code>--trusted-root&lt;/code> y &lt;code>--use-signing-config&lt;/code>; la consecuencia práctica es que el bundle &lt;strong>lleva dentro el material de verificación&lt;/strong> y permite verificar sin llamar a Rekor ni a Fulcio. &lt;strong>Rekor v2&lt;/strong> está en GA desde el 10 de octubre de 2025: reimplementación sobre &lt;em>tiles&lt;/em> que abarata mucho operar un log propio —se apagan Trillian log server y log signer, las lecturas se cachean en CDN— a cambio de recortar a dos tipos de entrada (&lt;code>hashedrekord&lt;/code> y &lt;code>dsse&lt;/code>) y quedarse sin índice de búsqueda. Requiere cosign 3.0.1+ o 2.6.0+; v1 sigue en paralelo y su congelación se anunciará con un año de antelación.&lt;/p>
&lt;h3 id="firmar-y-verificar-un-artefacto-de-modelo-en-oci">Firmar y verificar un artefacto de modelo en OCI&lt;/h3>
&lt;p>Sobre el artefacto del &lt;a href="https://blog.lo0.es/posts/registro-distribucion-modelos-oci-oras/">segundo artículo&lt;/a>, la operación es idéntica a la de una imagen: para el registro, un artefacto de modelo &lt;strong>es&lt;/strong> un objeto OCI con su digest.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Resolver el tag a digest UNA vez, en el pipeline. Se firma el digest, nunca el tag.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">oras resolve registro.interno/modelos/llama-70b-fin:v7
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># -&amp;gt; sha256:9f2a4c1e77b0d3a8...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Firma keyless desde CI (el token OIDC lo aporta el runner)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cosign sign --yes registro.interno/modelos/llama-70b-fin@sha256:9f2a4c1e...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Verificación: identidad exacta del workflow, emisor exacto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cosign verify &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --certificate-identity-regexp &lt;span class="s1">&amp;#39;^https://git.interno/plataforma/modelos/.*@refs/heads/main&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --certificate-oidc-issuer &lt;span class="s1">&amp;#39;https://git.interno&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> registro.interno/modelos/llama-70b-fin@sha256:9f2a4c1e...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>El error más frecuente es omitir &lt;code>--certificate-identity&lt;/code> y &lt;code>--certificate-oidc-issuer&lt;/code>, o ponerlos tan laxos que acepten cualquier identidad del proveedor. Sin esos dos flags acotados, &lt;strong>la verificación comprueba que alguien firmó, no que firmara quien debe&lt;/strong>: la diferencia entre &amp;ldquo;trae precinto&amp;rdquo; y &amp;ldquo;trae el precinto de nuestro matadero&amp;rdquo;.&lt;/p>
&lt;h3 id="el-problema-del-air-gap">El problema del air-gap&lt;/h3>
&lt;p>Keyless necesita un OIDC alcanzable al firmar y, en el modelo clásico, un Rekor alcanzable al verificar. En un CPD desconectado, tres estrategias:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Estrategia&lt;/th>
&lt;th>Qué se gana&lt;/th>
&lt;th>Qué cuesta&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Clave / PKI propia&lt;/strong> (&lt;code>cosign sign --key&lt;/code>)&lt;/td>
&lt;td>Funciona sin red; encaja con HSM y PKI corporativa&lt;/td>
&lt;td>Vuelve la custodia y rotación de claves de larga duración; sin log de transparencia no hay detección de firma no autorizada&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Sigstore privado&lt;/strong> (Fulcio + Rekor v2 + OIDC internos)&lt;/td>
&lt;td>Keyless completo y transparencia real dentro del perímetro&lt;/td>
&lt;td>Tres servicios más que operar, con su raíz TUF y su ciclo de rotación&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Bundle nuevo + verificación offline&lt;/strong>&lt;/td>
&lt;td>Verificación sin red con &lt;code>--offline&lt;/code> y &lt;code>--trusted-root&lt;/code> local&lt;/td>
&lt;td>Transportar y mantener actualizada la raíz de confianza por sneakernet&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">cosign verify --offline&lt;span class="o">=&lt;/span>&lt;span class="nb">true&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --trusted-root /etc/sigstore/trusted_root.json &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --certificate-identity-regexp &lt;span class="s1">&amp;#39;^https://git.interno/plataforma/modelos/.*&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --certificate-oidc-issuer &lt;span class="s1">&amp;#39;https://git.interno&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> registro.interno/modelos/llama-70b-fin@sha256:9f2a4c1e...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Dos advertencias. &lt;code>--insecure-ignore-tlog&lt;/code> existe y se usa mucho en air-gap, pero su nombre no engaña: &lt;strong>desactiva la comprobación de inclusión en el log de transparencia&lt;/strong>, que es justo lo que distingue a Sigstore de una PKI convencional; si se usa, se está haciendo firma con certificado, no Sigstore. Y hay fricción documentada: el issue 4550 de cosign describe la 3.0.2 intentando alcanzar el CDN de TUF pese a tener clave local y acceso solo a un Nexus interno. El air-gap funciona, pero no es el camino feliz.&lt;/p>
&lt;h2 id="firmar-un-modelo-no-es-firmar-un-fichero">Firmar un modelo no es firmar un fichero&lt;/h2>
&lt;p>Un modelo servible es un directorio: varios shards de safetensors, &lt;code>config.json&lt;/code>, tokenizer, quizá un &lt;code>chat_template.jinja&lt;/code>. Cambiar el &lt;code>config.json&lt;/code> —la longitud de contexto, el &lt;code>rope_scaling&lt;/code>— altera el comportamiento sin tocar un peso. Firmar solo los pesos deja la puerta abierta.&lt;/p>
&lt;p>La respuesta es la especificación &lt;strong>OpenSSF Model Signing (OMS)&lt;/strong>, publicada en junio de 2025 con contribución de Google, HiddenLayer, NVIDIA, Red Hat, Intel, Meta, IBM y Microsoft. Su diseño: una &lt;strong>firma separada&lt;/strong> que no modifica ni reempaqueta el contenido, sobre un &lt;strong>manifiesto&lt;/strong> que lista todos los ficheros por su hash (SHA-256 por defecto, BLAKE2b como alternativa), con una firma que cubre el manifiesto entero. Es deliberadamente &lt;strong>agnóstica de PKI&lt;/strong>: acepta claves desnudas, certificados autofirmados, PKI corporativa o Sigstore keyless. La implementación de referencia es &lt;code>model_signing&lt;/code>, de &lt;strong>sigstore/model-transparency&lt;/strong>, versión &lt;strong>1.1.1&lt;/strong> del 10 de octubre de 2025; la 1.1.0 añadió PKCS#11 (HSM), instancias privadas de Sigstore, BLAKE3 y trazas OpenTelemetry.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Firma todo el directorio: pesos, config y tokenizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">model_signing sign /modelos/llama-70b-fin --signature /modelos/llama-70b-fin/model.sig
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Verificación con identidad OIDC acotada&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">model_signing verify /modelos/llama-70b-fin &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --signature /modelos/llama-70b-fin/model.sig &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --identity &lt;span class="s1">&amp;#39;https://git.interno/plataforma/modelos/.github/workflows/publicar.yml@refs/heads/main&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --identity-provider &lt;span class="s1">&amp;#39;https://git.interno&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>El payload es un envoltorio DSSE con una declaración in-toto cuyos &lt;code>subjects&lt;/code> son los pares ruta-digest de cada fichero y cuyo &lt;code>predicateType&lt;/code> es &lt;code>https://model_signing/signature/v1.0&lt;/code>; el soporte de &lt;strong>shards de fichero&lt;/strong> permite hashear en trozos. Madurez sin adornos: el proyecto está en &lt;strong>sandbox&lt;/strong> de OpenSSF. La especificación es sólida y tiene detrás a los proveedores que importan —NVIDIA firma modelos en NGC con ella—, pero es el primer escalón formal y hay pocos verificadores independientes de la CLI de referencia.&lt;/p>
&lt;h3 id="la-aritmética-del-hashing-que-resulta-no-ser-el-problema">La aritmética del hashing, que resulta no ser el problema&lt;/h3>
&lt;p>¿Cuánto tarda en hashearse un modelo de cientos de gigas antes de cada arranque? Sea ( S ) el tamaño total, ( p ) los hilos en paralelo sobre shards distintos, ( r_{\text{cpu}} ) el caudal de hashing por hilo y ( r_{\text{io}} ) el de lectura del almacenamiento:&lt;/p>
&lt;p>$$t_{\text{hash}} = \frac{S}{\min\left(p \cdot r_{\text{cpu}},\ r_{\text{io}}\right)}$$&lt;/p>
&lt;p>Con un modelo denso de 70B en bf16 —unos 140 GB en una treintena de shards—, SHA-256 acelerado por SHA-NI ronda 1,5-2 GB/s por hilo. Con ocho hilos el término de CPU está en torno a 14 GB/s, muy por encima de lo que entrega un NVMe Gen4, del orden de 6 GB/s. &lt;strong>El mínimo lo fija el disco, no el hash&lt;/strong>: unos 23 segundos. Y ese es el mismo caudal que el loader va a consumir de todas formas para llevar los pesos a HBM: si la verificación ocurre en el mismo &lt;code>initContainer&lt;/code> que ya lee el artefacto, el coste marginal es de CPU, no de I/O. Lo caro no es verificar un modelo grande, sino haber puesto la verificación en un paso separado que lee el disco dos veces (el resto del presupuesto de arranque, en &lt;a href="https://blog.lo0.es/posts/acelerar-cold-start-carga-modelos-tensorizer/">el post de cold start&lt;/a>). Lo que sí tiene coste real es la &lt;strong>verificación incremental&lt;/strong>: si solo cambia un shard, el manifiesto permite comprobar únicamente ese, pero solo si la capa de distribución hace pull incremental. Con artefacto OCI y capas granuladas funciona; con un tarball monolítico, no.&lt;/p>
&lt;h2 id="procedencia-slsa-e-in-toto-sobre-un-pipeline-de-qlora">Procedencia: SLSA e in-toto sobre un pipeline de QLoRA&lt;/h2>
&lt;p>La firma dice &lt;em>quién&lt;/em> publicó; la procedencia dice &lt;em>cómo se produjo&lt;/em>. El marco es &lt;strong>SLSA&lt;/strong>, cuya &lt;strong>v1.2 se publicó el 24 de noviembre de 2025&lt;/strong>, compatible hacia atrás con la v1.1. Su novedad es el &lt;strong>Source track&lt;/strong>; el &lt;em>Build Environment track&lt;/em> y el &lt;em>Dependency track&lt;/em> siguen &lt;strong>en desarrollo&lt;/strong> — y el primero es exactamente el que habría ayudado en Ultralytics.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Nivel&lt;/th>
&lt;th>Qué exige SLSA&lt;/th>
&lt;th>Qué significa en un pipeline QLoRA&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Build L0&lt;/strong>&lt;/td>
&lt;td>Nada&lt;/td>
&lt;td>El adapter que alguien entrenó en su workstation&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Build L1&lt;/strong>&lt;/td>
&lt;td>Procedencia generada automáticamente: quién construyó, con qué proceso y con qué entradas de primer nivel. Puede ir sin firmar&lt;/td>
&lt;td>El job emite provenance con commit, dataset e hiperparámetros. Detecta errores, no ataques&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Build L2&lt;/strong>&lt;/td>
&lt;td>Lo anterior más build en plataforma alojada que &lt;strong>genera y firma&lt;/strong> la procedencia, validable por el consumidor&lt;/td>
&lt;td>El runner de CI firma con su identidad. Ya hay algo que un admission controller puede verificar&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Build L3&lt;/strong>&lt;/td>
&lt;td>Lo anterior más aislamiento entre ejecuciones y &lt;strong>material de firma inaccesible desde los pasos definidos por el usuario&lt;/strong>&lt;/td>
&lt;td>Runner efímero por job, sin secretos de firma al alcance del script de entrenamiento. Es el objetivo realista&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>in-toto&lt;/strong> es el formato en el que se expresa todo esto: graduó en la CNCF el &lt;strong>23 de abril de 2025&lt;/strong>, lo que en la práctica lo convierte en sustrato común de SLSA, de &lt;code>cosign attest&lt;/code> y del propio OMS. Sobre el flujo del &lt;a href="https://blog.lo0.es/posts/qlora-runbook-fine-tuning-serving/">runbook de QLoRA&lt;/a> y del &lt;a href="https://blog.lo0.es/posts/fine-tuning-continuo-produccion/">fine-tuning continuo&lt;/a>, la atestación útil es la que permite reproducir y auditar:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;_type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://in-toto.io/Statement/v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;subject&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;adapter-soporte-v7&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;digest&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;sha256&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;e3b0c44298fc1c149afbf4c8...&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;predicateType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://slsa.dev/provenance/v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;predicate&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;buildDefinition&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;buildType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://interno/build-types/qlora-finetune@v2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;externalParameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;modeloBase&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;registro.interno/modelos/llama-70b@sha256:9f2a...&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dataset&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;lakefs://corpus-soporte@commit-4c1f9e&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;hiperparametros&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;rank&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;alpha&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;lr&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">0.0002&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;epochs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;quant&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;nf4&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;internalParameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;gpu&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;4xH100-SXM-80GB&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;cuda&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;12.6&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;torch&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2.8.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;imagenEntrenamiento&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;registro.interno/ci/qlora@sha256:71ca...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;resolvedDependencies&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;uri&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;git+https://git.interno/plataforma/finetune@a91c3f&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;digest&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;gitCommit&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;a91c3f...&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;runDetails&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;builder&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://git.interno/plataforma/runners/gpu-efimero&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;metadata&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;invocationId&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;run-2026-07-19-0041&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;startedOn&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2026-07-19T02:14:33Z&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Los cinco campos que hacen falta y casi nunca están completos: &lt;strong>hash del modelo base&lt;/strong>, &lt;strong>identificador inmutable del dataset&lt;/strong> (aquí un commit de lakeFS, en la línea del &lt;a href="https://blog.lo0.es/posts/data-versioning-dvc-lakefs/">versionado de datos&lt;/a>), &lt;strong>hiperparámetros&lt;/strong>, &lt;strong>hardware y versiones del stack&lt;/strong>, y &lt;strong>commit del código&lt;/strong>. Sin el primero no se reconstruye la cadena hasta el modelo original; sin el segundo, el bucle de &lt;a href="https://blog.lo0.es/posts/retrain-cerrar-el-bucle-feedback-dataset-adapter/">retrain&lt;/a> queda sin evidencia reproducible. Y la advertencia obligatoria: &lt;strong>SLSA no dice nada sobre la calidad del dataset&lt;/strong>; Build L3 garantiza que nadie manipuló el build, no que el corpus estuviera limpio.&lt;/p>
&lt;h2 id="aibom-spdx-301-frente-a-cyclonedx-17">AIBOM: SPDX 3.0.1 frente a CycloneDX 1.7&lt;/h2>
&lt;p>Si el manifiesto es el precinto y la procedencia el registro sanitario, el AIBOM es la etiqueta de ingredientes. Hay dos formatos, y la comparativa honesta es menos halagüeña de lo que sugiere la literatura de proveedor. &lt;strong>SPDX 3.0&lt;/strong> (abril de 2024), con parche &lt;strong>3.0.1&lt;/strong> el 17 de diciembre de 2024, reorganizó la especificación en &lt;strong>perfiles&lt;/strong>, dos relevantes aquí: &lt;code>AI&lt;/code> y &lt;code>Dataset&lt;/code>. El perfil AI define sobre &lt;code>AIPackage&lt;/code> campos como &lt;code>typeOfModel&lt;/code>, &lt;code>hyperparameter&lt;/code>, &lt;code>informationAboutTraining&lt;/code>, &lt;code>metric&lt;/code>, &lt;code>safetyRiskAssessment&lt;/code> y &lt;code>limitation&lt;/code>, más —singularidad suya— cuatro campos de &lt;strong>consumo energético&lt;/strong> desglosados en entrenamiento, fine-tuning e inferencia. La v3.1 lleva en RC desde enero de 2025 sin GA, y la 3.0 está en trámite ISO como ISO/IEC DIS 5962 (la norma vigente sigue siendo la 2.2.1). &lt;strong>CycloneDX 1.7&lt;/strong> se publicó el 21 de octubre de 2025 y fue ratificado como &lt;strong>ECMA-424, 2ª edición, en diciembre de 2025&lt;/strong>; su ML-BOM se apoya en el tipo &lt;code>machine-learning-model&lt;/code> y el objeto &lt;code>modelCard&lt;/code>.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Criterio&lt;/th>
&lt;th>SPDX 3.0.1&lt;/th>
&lt;th>CycloneDX 1.7&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Estandarización formal&lt;/td>
&lt;td>ISO/IEC DIS 5962 en curso; norma vigente es la 2.2.1&lt;/td>
&lt;td>ECMA-424 2ª ed. (diciembre de 2025)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Modelo de IA&lt;/td>
&lt;td>Perfil &lt;code>AI&lt;/code> sobre &lt;code>AIPackage&lt;/code>&lt;/td>
&lt;td>&lt;code>machine-learning-model&lt;/code> + &lt;code>modelCard&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Dataset&lt;/td>
&lt;td>Perfil &lt;code>Dataset&lt;/code> dedicado&lt;/td>
&lt;td>&lt;code>data&lt;/code> y &lt;code>modelParameters.datasets&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Energía&lt;/td>
&lt;td>Cuatro campos desglosados (único)&lt;/td>
&lt;td>No cubierto de forma nativa&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Uso previsto y ética&lt;/td>
&lt;td>&lt;code>limitation&lt;/code>, &lt;code>safetyRiskAssessment&lt;/code>&lt;/td>
&lt;td>&lt;code>considerations&lt;/code> (más cercano a Model Cards)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ergonomía&lt;/td>
&lt;td>Modelo rico, verboso, curva alta&lt;/td>
&lt;td>JSON compacto, más adopción en tooling&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Encaje con VEX&lt;/td>
&lt;td>Vía perfil &lt;code>Security&lt;/code>&lt;/td>
&lt;td>Nativo, alineado con CSAF VEX 2.0&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;bomFormat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;CycloneDX&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;specVersion&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.7&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;components&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;machine-learning-model&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;bom-ref&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;modelo/adapter-soporte-v7&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;adapter-soporte&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;7.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;hashes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nt">&amp;#34;alg&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;SHA-256&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;e3b0c44298fc1c14...&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;licenses&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nt">&amp;#34;license&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Apache-2.0&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;modelCard&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;modelParameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;task&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;text-generation&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;modelArchitecture&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;llama-70b + LoRA r=16&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;datasets&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;dataset&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;corpus-soporte&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;contents&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;lakefs://corpus-soporte@commit-4c1f9e&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;quantitativeAnalysis&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;performanceMetrics&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;exactitud-eval-interna&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;value&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;0.83&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;slice&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;soporte-es&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;considerations&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;useCases&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;asistencia interna a agentes de soporte&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;technicalLimitations&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;no evaluado fuera de castellano&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Qué se genera de verdad hoy.&lt;/strong> Un tooling automático rellena bien nombre, versión, hashes, licencias y dependencias del entorno de inferencia: eso es un SBOM clásico y Trivy o Syft lo hacen solos. Lo que &lt;strong>solo puede venir del pipeline&lt;/strong>, porque ningún escáner lo infiere de los bytes: dataset, hiperparámetros, métricas, modelo base, energía. Y lo que es &lt;strong>puramente humano&lt;/strong>: limitaciones, usos previstos, consideraciones éticas. La conclusión es incómoda: &lt;strong>un AIBOM generado a posteriori por una herramienta que mira el artefacto es, en su mayor parte, un documento vacío con estructura válida&lt;/strong>. El AIBOM útil lo emite el job de entrenamiento —el único que conoce esos campos— y se firma junto con el artefacto.&lt;/p>
&lt;h2 id="regulación-qué-obliga-y-desde-cuándo-exactamente">Regulación: qué obliga, y desde cuándo exactamente&lt;/h2>
&lt;p>Conviene ser quirúrgico con las fechas, porque han cambiado en 2026 y mucha documentación en circulación está desactualizada.&lt;/p>
&lt;h3 id="eu-ai-act">EU AI Act&lt;/h3>
&lt;p>Las obligaciones de los &lt;strong>proveedores de modelos de propósito general (GPAI)&lt;/strong> aplican desde el &lt;strong>2 de agosto de 2025&lt;/strong>. El artículo 53 exige documentación técnica conforme al &lt;strong>Anexo XI&lt;/strong>, información para proveedores aguas abajo conforme al &lt;strong>Anexo XII&lt;/strong>, una política de derechos de autor y un resumen público del contenido de entrenamiento. El Anexo XI, sección 1, pide explícitamente las especificaciones del proceso de entrenamiento, &lt;strong>información sobre los datos usados para entrenamiento, prueba y validación, incluyendo su tipo y procedencia&lt;/strong>, los recursos computacionales empleados (por ejemplo, operaciones en coma flotante), el tiempo de entrenamiento y el consumo energético conocido o estimado. Quien hubiera puesto un modelo en el mercado antes de esa fecha tiene hasta el 2 de agosto de 2027.&lt;/p>
&lt;p>El cambio de 2026: el &lt;strong>Reglamento (UE) 2026/1744&lt;/strong>, el &amp;ldquo;Digital Omnibus&amp;rdquo; de IA, se publicó en el DOUE el &lt;strong>24 de julio de 2026&lt;/strong> y entró en vigor el &lt;strong>27 de julio de 2026&lt;/strong>. El Capítulo III para &lt;strong>alto riesgo del Anexo III&lt;/strong> pasa del 2 de agosto de 2026 al &lt;strong>2 de diciembre de 2027&lt;/strong>; el &lt;strong>alto riesgo del Anexo I&lt;/strong> (IA como componente de seguridad de productos regulados), al &lt;strong>2 de agosto de 2028&lt;/strong>; el &lt;strong>2 de diciembre de 2026&lt;/strong> entran nuevas prohibiciones del artículo 5 y el marcado legible por máquina para GPAI. Las obligaciones de GPAI de los artículos 51 a 56 &lt;strong>no se retrasan&lt;/strong>.&lt;/p>
&lt;p>La lectura para un arquitecto: si afinas un modelo y lo pones en el mercado, el Anexo XI es exigible &lt;strong>ya&lt;/strong>, y sus campos son casi literalmente los de una atestación SLSA más un AIBOM. Si tu caso es de alto riesgo tienes año y medio más de margen del que creías, pero ese margen es para los estándares armonizados, no para empezar tarde (&lt;a href="https://blog.lo0.es/posts/eu-ai-act-mapeo-arquitectura-llm-on-premise/">detalle en el post del AI Act&lt;/a>).&lt;/p>
&lt;h3 id="cyber-resilience-act">Cyber Resilience Act&lt;/h3>
&lt;p>La CRA entró en vigor el &lt;strong>10 de diciembre de 2024&lt;/strong>; las obligaciones de notificación del artículo 14 aplican desde el &lt;strong>11 de septiembre de 2026&lt;/strong> y la aplicación plena desde el &lt;strong>11 de diciembre de 2027&lt;/strong>. Lo que exige, en el Anexo I, Parte II, punto 1, es una &lt;strong>lista de materiales de software en un formato comúnmente utilizado y legible por máquina &amp;ldquo;que cubra al menos las dependencias de primer nivel&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;p>Tres matices que se citan mal. &amp;ldquo;Al menos las dependencias de primer nivel&amp;rdquo; es un suelo bajísimo: no exige el árbol transitivo. El SBOM &lt;strong>no tiene que ser público&lt;/strong> —el considerando 77 lo dice expresamente—: es documentación interna que las autoridades pueden requerir. Y la CRA &lt;strong>no nombra ningún formato&lt;/strong>; la Comisión se reserva concretarlo por acto de ejecución, y la guía más precisa hoy es la BSI TR-03183-2, que acepta CycloneDX 1.6+ o SPDX 3.0.1+. El punto clave: &lt;strong>la CRA habla de SBOM, no de AIBOM&lt;/strong>; que el artefacto de modelo caiga bajo su paraguas es interpretación, no texto.&lt;/p>
&lt;h3 id="encaje-con-ens-e-isoiec-42001">Encaje con ENS e ISO/IEC 42001&lt;/h3>
&lt;p>Nada de esto es higiene voluntaria. La firma y su verificación en admission materializan &lt;code>op.exp.6&lt;/code> y &lt;code>op.ext.3&lt;/code> del ENS (cadena de suministro) y el control A.10 de ISO/IEC 42001; la atestación de procedencia cubre &lt;code>op.exp.2&lt;/code> y el A.6 (ciclo de vida del sistema de IA); el AIBOM con dataset e hiperparámetros es &lt;code>op.exp.1&lt;/code> (inventario) y A.7 (datos); y el log de transparencia, &lt;code>op.exp.8&lt;/code>. La evidencia que pide un auditor de &lt;a href="https://blog.lo0.es/posts/iso-42001-aims-llm-on-premise/">ISO/IEC 42001&lt;/a> sobre el ciclo de vida es, en buena medida, el mismo JSON que emite el pipeline; el desglose control a control, en el &lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">post de controles técnicos&lt;/a>.&lt;/p>
&lt;h2 id="verificación-en-el-clúster-el-muelle-de-recepción">Verificación en el clúster: el muelle de recepción&lt;/h2>
&lt;p>Nada de lo anterior vale si nadie comprueba el precinto en la puerta. &lt;strong>Kyverno&lt;/strong> graduó en la CNCF el &lt;strong>16 de marzo de 2026&lt;/strong>; su 1.17 (febrero de 2026) promovió a v1 las políticas CEL —incluida &lt;code>ImageValidatingPolicy&lt;/code>— y marcó &lt;code>ClusterPolicy&lt;/code> como obsoleta, y la &lt;strong>1.18&lt;/strong> (24 de abril de 2026) pulió la verificación de imágenes. La alternativa, el &lt;strong>policy-controller de Sigstore&lt;/strong>, va por &lt;strong>v0.15.1&lt;/strong> (26 de marzo de 2026), que subió de cosign v2 a v3 y migró a go-tuf v2 —relevante para quien opera un Sigstore privado con roles delegados—.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">policies.kyverno.io/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ImageValidatingPolicy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">modelos-firmados-y-con-provenance&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validationActions: [Deny] # fail-closed&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">no&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">admite, no audita&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">failurePolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Fail &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># si el webhook falla, se deniega&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">webhookConfiguration&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">timeoutSeconds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">20&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># el pull de la firma puede tardar&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchConstraints&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resourceRules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">apiGroups&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apiVersions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;v1&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;pods&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">operations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;CREATE&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;UPDATE&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">matchImageReferences&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">glob&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;registro.interno/modelos/*&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">attestors&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ci-plataforma&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cosign&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">keyless&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">identities&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">issuer&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://git.interno&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">subject&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://git.interno/plataforma/modelos/.github/workflows/publicar.yml@refs/heads/main&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ctlog&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://rekor.interno&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">attestations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">slsaProvenance&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">intoto&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://slsa.dev/provenance/v1&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">validations&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">expression&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">&amp;gt;-&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> images.containers.map(image,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> verifyImageSignatures(image, [attestors.ci_plataforma])).all(e, e &amp;gt; 0)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">message&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Artefacto de modelo sin firma valida de la CI de plataforma&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">expression&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">&amp;gt;-&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> images.containers.map(image,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> verifyAttestationSignatures(image, attestations.slsaProvenance,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> [attestors.ci_plataforma])).all(e, e &amp;gt; 0)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">message&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Falta atestacion SLSA de procedencia&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="verificar-el-modelo-no-solo-la-imagen">Verificar el modelo, no solo la imagen&lt;/h3>
&lt;p>Esa política cubre la &lt;strong>imagen&lt;/strong> del contenedor de serving. El modelo se descarga después, en el &lt;code>initContainer&lt;/code>, donde el admission controller ya no llega. El patrón que funciona es verificar ahí, antes de escribir en el volumen compartido:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">initContainers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">traer-y-verificar-modelo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">registro.interno/plataforma/oras-cosign@sha256:4b7e...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;/bin/sh&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;-ec&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">args&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="p">|&lt;/span>&lt;span class="sd">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> oras pull registro.interno/modelos/llama-70b-fin@sha256:9f2a... -o /modelos
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> cosign verify --offline=true \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> --trusted-root /etc/sigstore/trusted_root.json \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> --certificate-oidc-issuer https://git.interno \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> --certificate-identity-regexp &amp;#39;^https://git.interno/plataforma/modelos/.*&amp;#39; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> registro.interno/modelos/llama-70b-fin@sha256:9f2a...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> model_signing verify /modelos --signature /modelos/model.sig \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> --identity-provider https://git.interno \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sd"> --identity &amp;#39;https://git.interno/plataforma/modelos/.github/workflows/publicar.yml@refs/heads/main&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumeMounts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- {&lt;span class="w"> &lt;/span>&lt;span class="nt">name: modelos, mountPath&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/modelos }&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- {&lt;span class="w"> &lt;/span>&lt;span class="nt">name: sigstore-root, mountPath: /etc/sigstore, readOnly&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w"> &lt;/span>}&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>La doble verificación no es redundante: &lt;code>cosign verify&lt;/code> cubre el artefacto OCI tal como está en el registro, y &lt;code>model_signing verify&lt;/code> cubre el &lt;strong>contenido desempaquetado&lt;/strong> tal como lo va a leer el motor. Si alguien monta un &lt;code>ConfigMap&lt;/code> que sobreescribe el &lt;code>config.json&lt;/code> después del pull, la primera pasa y la segunda no.&lt;/p>
&lt;h3 id="fail-closed-frente-a-fail-open-y-lo-que-cuesta">Fail-closed frente a fail-open, y lo que cuesta&lt;/h3>
&lt;p>&lt;code>failurePolicy: Fail&lt;/code> con &lt;code>validationActions: [Deny]&lt;/code> significa que si el webhook no responde &lt;strong>no arranca nada&lt;/strong>: lo correcto desde seguridad, y exactamente lo que tumba un clúster un domingo por la mañana. La postura defendible: fail-closed en el namespace de producción, con el controlador en alta disponibilidad y su propio namespace &lt;strong>excluido&lt;/strong> de sus políticas para poder recuperarlo; &lt;code>Audit&lt;/code> durante la adopción, la misma regla de &amp;ldquo;observar primero, bloquear después&amp;rdquo; que aplicamos con Tetragon en el &lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">hardening&lt;/a>; y un &lt;strong>procedimiento de excepción escrito y con caducidad&lt;/strong>, porque el día del hotfix a las tres de la mañana alguien se va a saltar la política y es mejor que lo haga por un camino auditado.&lt;/p>
&lt;p>Sobre latencia, lo importante es que &lt;strong>es coste de arranque, no de request&lt;/strong>: se verifica una vez por pod. Un benchmark de terceros de marzo de 2026 sobre policy-controller v0.15 reporta 92 ms en p50 y 184 ms en p99 para imágenes firmadas internamente, con picos de hasta 4 segundos en despliegues masivos. Conviene tomarlo por lo que es —&lt;strong>medición de un tercero, sin réplica independiente publicada&lt;/strong>—, pero el orden de magnitud es coherente: centenares de milisegundos frente a los minutos que tarda un pod en cargar 140 GB a HBM.&lt;/p>
&lt;p>Como segunda red, &lt;strong>Harbor&lt;/strong> guarda las firmas de cosign como artefactos referrer y puede impedir el despliegue de lo no firmado por política de proyecto. Y en el &lt;a href="https://blog.lo0.es/posts/gitops-stack-inferencia-llm-flux/">GitOps con Flux&lt;/a>, lo que cierra el círculo es referenciar &lt;strong>siempre por digest&lt;/strong> y verificar la firma del artefacto OCI en la reconciliación: dos comprobaciones independientes en momentos distintos.&lt;/p>
&lt;h2 id="mapa-de-decisión-qué-poner-en-qué-orden">Mapa de decisión: qué poner, en qué orden&lt;/h2>
&lt;p>Por retorno decreciente sobre esfuerzo:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pin por digest en todo el GitOps.&lt;/strong> Una tarde; sin esto, lo demás es decorativo.&lt;/li>
&lt;li>&lt;strong>Firma de imágenes con cosign keyless desde CI y &lt;code>ImageValidatingPolicy&lt;/code> en &lt;code>Audit&lt;/code>.&lt;/strong> Días. Revela cuánto de tu clúster no está firmado, que suele ser una sorpresa.&lt;/li>
&lt;li>&lt;strong>Firma del artefacto de modelo con &lt;code>model_signing&lt;/code>&lt;/strong> en el job que lo publica. Días. Mata el modelo subido a mano un viernes.&lt;/li>
&lt;li>&lt;strong>Paso a &lt;code>Deny&lt;/code>&lt;/strong> en el namespace de inferencia, con excepciones auditadas y controlador en HA.&lt;/li>
&lt;li>&lt;strong>Atestación SLSA, objetivo Build L2 y luego L3.&lt;/strong> Semanas: exige runners efímeros y sacar el material de firma del alcance del script de entrenamiento.&lt;/li>
&lt;li>&lt;strong>AIBOM emitido desde el pipeline&lt;/strong>, con los cinco campos que solo él conoce. Semanas, y sobre todo trabajo de proceso.&lt;/li>
&lt;li>&lt;strong>Sigstore privado&lt;/strong>, solo con requisito real de air-gap y con los seis anteriores hechos.&lt;/li>
&lt;/ol>
&lt;p>Entre &lt;strong>Kyverno y policy-controller&lt;/strong>: Kyverno si hay o va a haber un programa de política más amplio —Pod Security, etiquetas, cuotas—, por unificación y por su estado graduado; policy-controller si la organización es Sigstore-céntrica y no quiere más motor de políticas que el imprescindible. Entre &lt;strong>keyless y clave&lt;/strong>: keyless si CI alcanza un OIDC, aunque sea interno; clave con HSM en air-gap estricto donde no se vaya a operar un Fulcio propio.&lt;/p>
&lt;h2 id="trampas-operativas">Trampas operativas&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Verificar sin acotar la identidad.&lt;/strong> &lt;code>cosign verify&lt;/code> sin &lt;code>--certificate-identity&lt;/code> ni &lt;code>--certificate-oidc-issuer&lt;/code>, o con un regexp que acepta cualquier repositorio del proveedor, es teatro de seguridad. La trampa número uno y la más silenciosa.&lt;/li>
&lt;li>&lt;strong>Bugs fail-closed en el propio verificador.&lt;/strong> El issue 16435 de Kyverno, abierto el 2 de julio de 2026 contra la 1.18.0, describe dos regresiones simultáneas en &lt;code>ImageValidatingPolicy&lt;/code> con atestadores de clave y certificado: un SIGSEGV por puntero nulo y un fallo de tlog con el mensaje &lt;code>not enough verified log entries from transparency log: 0 &amp;lt; 1&lt;/code>. Ambas deniegan imágenes legítimas o tumban el controlador. Corregido para la 1.19, pero la lección es permanente: &lt;strong>el verificador es un componente crítico y sus regresiones son indisponibilidad&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>La raíz de confianza que caduca en air-gap.&lt;/strong> Se copió a mano hace nueve meses, nadie lleva el calendario, y un día la verificación falla sin que nadie haya tocado nada.&lt;/li>
&lt;li>&lt;strong>El AIBOM que nadie regenera.&lt;/strong> Se emite en el despliegue inicial, se afina el modelo tres veces y sigue describiendo la versión uno. Un inventario desactualizado es peor que ninguno: genera confianza injustificada.&lt;/li>
&lt;li>&lt;strong>Verificar la imagen y olvidar el modelo.&lt;/strong> Lo más habitual: el contenedor de vLLM impecablemente firmado, y los 140 GB que carga vienen de un bucket sin verificar.&lt;/li>
&lt;/ul>
&lt;h2 id="lo-que-esto-no-demuestra">Lo que esto NO demuestra&lt;/h2>
&lt;p>&lt;strong>Una firma dice quién publicó, no que el modelo sea bueno ni seguro.&lt;/strong> Es una afirmación de autoría, no de calidad. Ultralytics lo documenta: cuatro releases con criptominero y atestaciones válidas. Si el entorno de build está comprometido, la firma certifica fielmente el artefacto comprometido.&lt;/p>
&lt;p>&lt;strong>Un modelo firmado puede tener puerta trasera.&lt;/strong> Nada en Sigstore, OMS o SLSA examina los pesos. Un backdoor entrenado por quien tiene acceso legítimo al pipeline atraviesa toda la cadena sin encender una alarma; la defensa es evaluación adversarial y &lt;a href="https://blog.lo0.es/posts/canary-blue-green-shadow-modelos-llm/">canary o shadow&lt;/a>, no criptografía. Y &lt;strong>SLSA no dice nada de la calidad del dataset&lt;/strong>: un pipeline formalmente perfecto sobre datos envenenados produce un modelo envenenado con procedencia impecable.&lt;/p>
&lt;p>&lt;strong>El AIBOM es tan bueno como el proceso que lo genera.&lt;/strong> Los campos que importan no los infiere ninguna herramienta. &lt;strong>Y el coste operativo es real y recurrente&lt;/strong>: rotación de claves y de raíces TUF, incidentes de verificación de madrugada, ruido de política durante la adopción, y el trabajo continuo de mantener un inventario que nadie lee hasta que hay auditoría.&lt;/p>
&lt;p>&lt;strong>El reparto de madurez a julio de 2026.&lt;/strong> Maduro y desplegable: Sigstore y cosign sobre artefactos OCI, Kyverno y policy-controller como admission control, in-toto como formato graduado en CNCF, el pin por digest. Utilizable con criterio: OMS y &lt;code>model_signing&lt;/code> (especificación sólida y respaldo industrial fuerte, pero proyecto en sandbox), SLSA Build L2-L3 en fine-tuning, CycloneDX ML-BOM. Todavía trabajo en curso: los tracks de &lt;em>Build Environment&lt;/em> y &lt;em>Dependency&lt;/em> de SLSA —los que cubrirían justamente el escenario Ultralytics—, el tooling que rellena un AIBOM automáticamente, y toda la detección de backdoors en pesos, que hoy es literatura y no producto.&lt;/p>
&lt;h2 id="para-una-factoría-de-inferencia">Para una factoría de inferencia&lt;/h2>
&lt;p>&lt;strong>Primera: el &lt;code>initContainer&lt;/code> es tu muelle de recepción, y hoy probablemente no comprueba nada.&lt;/strong> El admission controller mira la imagen; el modelo entra después por una puerta lateral. Añadir ahí &lt;code>cosign verify --offline&lt;/code> y &lt;code>model_signing verify&lt;/code> cuesta un par de tardes, cabe en el presupuesto de arranque en frío —23 segundos de hashing sobre un caudal de disco que ya estás pagando— y cierra el agujero más grande de la mayoría de despliegues.&lt;/p>
&lt;p>&lt;strong>Segunda: fija por digest hoy, firma mañana.&lt;/strong> Si solo cabe una cosa este trimestre, es eliminar los tags mutables del GitOps: es barato, no rompe nada y convierte &amp;ldquo;confío en el registro&amp;rdquo; en &amp;ldquo;confío en estos bytes concretos&amp;rdquo;. La firma añade la identidad del emisor encima, pero sin digest no tiene de qué agarrarse.&lt;/p>
&lt;p>&lt;strong>Tercera: exige la atestación a quien te entrega el modelo, aunque sea el equipo de al lado.&lt;/strong> Una factoría de inferencia consume lo que produce otro, y ese contrato debería ser explícito: firma de una identidad de CI conocida, atestación con hash del modelo base y commit del dataset, y AIBOM emitido desde el pipeline. No es burocracia: es lo que ya exige el Anexo XI del AI Act, en vigor, y lo que permite responder en veinte minutos —y no en dos semanas— cuando alguien pregunta qué hay exactamente detrás del endpoint.&lt;/p>
&lt;p>La cadena tiene ya tres eslabones: sabes &lt;strong>cómo se sirve&lt;/strong> el modelo, &lt;strong>de dónde salen&lt;/strong> sus bytes y &lt;strong>por qué te fías&lt;/strong> de ellos. Queda la última pregunta: cuando ese pod arranca con el modelo verificado, ¿quién es exactamente ese pod frente al resto del sistema, y hasta qué punto puedes confiar en la máquina donde se ejecuta? El cuarto artículo entra en identidad de carga de trabajo con &lt;a href="https://blog.lo0.es/posts/identidad-aislamiento-spiffe-confidential-containers/">SPIFFE/SPIRE y aislamiento con Confidential Containers&lt;/a> — porque un modelo verificado, servido por un proceso no identificado sobre un host que no puedes atestiguar, deja la cadena abierta justo en el último eslabón.&lt;/p>
&lt;h2 id="ver-también">Ver también&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/posts/registro-distribucion-modelos-oci-oras/">Cadena de confianza del modelo (2/4): registro y distribución con OCI y ORAS&lt;/a> — de dónde salen los bytes que aquí firmamos.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/identidad-aislamiento-spiffe-confidential-containers/">Cadena de confianza del modelo (4/4): SPIFFE y Confidential Containers&lt;/a> — quién sirve el modelo verificado y dónde se ejecuta.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/hardening-secretos-stack-llm-soberano/">Hardening y secretos del stack LLM soberano&lt;/a> — la cadena de suministro de imágenes que aquí extendemos al modelo.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/gitops-stack-inferencia-llm-flux/">GitOps del stack de inferencia con Flux&lt;/a> — donde se materializan el pin por digest y la verificación en reconciliación.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/iso-42001-aims-llm-on-premise/">ISO/IEC 42001: el AIMS del LLM on-premise&lt;/a> — el marco que convierte estas atestaciones en evidencia auditable.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/eu-ai-act-mapeo-arquitectura-llm-on-premise/">EU AI Act: mapeo sobre la arquitectura LLM on-premise&lt;/a> — artículos y anexos aplicables.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">Controles técnicos: ENS × ISO 42001 × EU AI Act&lt;/a> — la correspondencia control a control.&lt;/li>
&lt;/ul>
&lt;h2 id="fuentes">Fuentes&lt;/h2>
&lt;ul>
&lt;li>Sigstore, &lt;em>Releases · sigstore/cosign&lt;/em> (v3.1.1, 9-6-2026) — &lt;a href="https://github.com/sigstore/cosign/releases">https://github.com/sigstore/cosign/releases&lt;/a>&lt;/li>
&lt;li>Sigstore Blog, &lt;em>Cosign v3 is now available&lt;/em> (8-10-2025) — &lt;a href="https://blog.sigstore.dev/cosign-3-0-available/">https://blog.sigstore.dev/cosign-3-0-available/&lt;/a>&lt;/li>
&lt;li>Sigstore Blog, &lt;em>Rekor v2 GA — Cheaper to run, simpler to maintain&lt;/em> — &lt;a href="https://blog.sigstore.dev/rekor-v2-ga/">https://blog.sigstore.dev/rekor-v2-ga/&lt;/a>&lt;/li>
&lt;li>Some Natalie, &lt;em>Verifying Cosign signatures offline&lt;/em> — &lt;a href="https://some-natalie.dev/blog/cosign-disconnected/">https://some-natalie.dev/blog/cosign-disconnected/&lt;/a>&lt;/li>
&lt;li>sigstore/cosign, &lt;em>Issue 4550: Cosign 3.0.2 keeps reaching out to the TUF CDN&lt;/em> — &lt;a href="https://github.com/sigstore/cosign/issues/4550">https://github.com/sigstore/cosign/issues/4550&lt;/a>&lt;/li>
&lt;li>OpenSSF, &lt;em>An Introduction to the OpenSSF Model Signing (OMS) Specification&lt;/em> — &lt;a href="https://openssf.org/blog/2025/06/25/an-introduction-to-the-openssf-model-signing-oms-specification/">https://openssf.org/blog/2025/06/25/an-introduction-to-the-openssf-model-signing-oms-specification/&lt;/a>&lt;/li>
&lt;li>Sigstore, &lt;em>model-transparency — README y releases (model_signing 1.1.1)&lt;/em> — &lt;a href="https://github.com/sigstore/model-transparency/blob/main/README.md">https://github.com/sigstore/model-transparency/blob/main/README.md&lt;/a>&lt;/li>
&lt;li>SLSA, &lt;em>Announcing SLSA v1.2&lt;/em> y &lt;em>Build track basics&lt;/em> — &lt;a href="https://slsa.dev/blog/2025/11/announce-slsa-v1.2">https://slsa.dev/blog/2025/11/announce-slsa-v1.2&lt;/a>&lt;/li>
&lt;li>CNCF, &lt;em>Graduation of the in-toto security framework&lt;/em> — &lt;a href="https://www.cncf.io/announcements/2025/04/23/cncf-announces-graduation-of-in-toto-security-framework-enhancing-software-supply-chain-integrity-across-industries/">https://www.cncf.io/announcements/2025/04/23/cncf-announces-graduation-of-in-toto-security-framework-enhancing-software-supply-chain-integrity-across-industries/&lt;/a>&lt;/li>
&lt;li>SPDX, &lt;em>AI profile — SPDX Specification 3.0.1&lt;/em> — &lt;a href="https://spdx.github.io/spdx-spec/v3.0.1/model/AI/AI/">https://spdx.github.io/spdx-spec/v3.0.1/model/AI/AI/&lt;/a>&lt;/li>
&lt;li>CycloneDX, &lt;em>CycloneDX v1.7 released&lt;/em> (y ratificación ECMA-424 2ª ed.) — &lt;a href="https://cyclonedx.org/news/cyclonedx-v1.7-released/">https://cyclonedx.org/news/cyclonedx-v1.7-released/&lt;/a>&lt;/li>
&lt;li>EU Artificial Intelligence Act, &lt;em>Article 53 y Annex XI&lt;/em> — &lt;a href="https://artificialintelligenceact.eu/article/53/">https://artificialintelligenceact.eu/article/53/&lt;/a>&lt;/li>
&lt;li>NicFab, &lt;em>Digital Omnibus on AI: Regulation (EU) 2026/1744 published in the Official Journal&lt;/em> — &lt;a href="https://www.nicfab.eu/en/posts/digital-omnibus-ai-official-journal/">https://www.nicfab.eu/en/posts/digital-omnibus-ai-official-journal/&lt;/a>&lt;/li>
&lt;li>cyberresilienceact.eu, &lt;em>The Cyber Resilience Act Explained: Scope, Classes &amp;amp; Deadlines&lt;/em> — &lt;a href="https://www.cyberresilienceact.eu/explained.html">https://www.cyberresilienceact.eu/explained.html&lt;/a>&lt;/li>
&lt;li>CRA Decoded, &lt;em>CRA SBOM Requirements: What&amp;rsquo;s Mandated, What&amp;rsquo;s Optional&lt;/em> — &lt;a href="https://medium.com/@cra-decoded/cra-sbom-requirements-whats-mandated-what-s-optional-and-what-s-still-unclear-6de9270666de">https://medium.com/@cra-decoded/cra-sbom-requirements-whats-mandated-what-s-optional-and-what-s-still-unclear-6de9270666de&lt;/a>&lt;/li>
&lt;li>Kyverno, &lt;em>Announcing Kyverno Release 1.18&lt;/em> e &lt;em>Issue 16435&lt;/em> — &lt;a href="https://kyverno.io/blog/2026/04/24/announcing-kyverno-release-1.18/">https://kyverno.io/blog/2026/04/24/announcing-kyverno-release-1.18/&lt;/a>&lt;/li>
&lt;li>Safeguard, &lt;em>Sigstore Policy Controller v0.15 Admission Review 2026&lt;/em> — &lt;a href="https://safeguard.sh/resources/blog/sigstore-policy-controller-v0-15-2026">https://safeguard.sh/resources/blog/sigstore-policy-controller-v0-15-2026&lt;/a>&lt;/li>
&lt;li>JFrog, &lt;em>Malicious Hugging Face ML Models with Silent Backdoor&lt;/em> — &lt;a href="https://jfrog.com/blog/data-scientists-targeted-by-malicious-hugging-face-ml-models-with-silent-backdoor/">https://jfrog.com/blog/data-scientists-targeted-by-malicious-hugging-face-ml-models-with-silent-backdoor/&lt;/a>&lt;/li>
&lt;li>ReversingLabs, &lt;em>Novel ML Malware (nullifAI) on Hugging Face&lt;/em> — &lt;a href="https://www.reversinglabs.com/press-releases/reversinglabs-identifies-novel-ml-malware-hosted-on-leading-hugging-face-ai-model-platform">https://www.reversinglabs.com/press-releases/reversinglabs-identifies-novel-ml-malware-hosted-on-leading-hugging-face-ai-model-platform&lt;/a>&lt;/li>
&lt;li>EleutherAI / Hugging Face, &lt;em>Safetensors audited as really safe (Trail of Bits)&lt;/em> — &lt;a href="https://blog.eleuther.ai/safetensors-security-audit/">https://blog.eleuther.ai/safetensors-security-audit/&lt;/a>&lt;/li>
&lt;li>Socket, &lt;em>Ultralytics PyPI Package Compromised Through GitHub Actions Cache Poisoning&lt;/em> — &lt;a href="https://socket.dev/blog/ultralytics-pypi-package-compromised-through-github-actions-cache-poisoning">https://socket.dev/blog/ultralytics-pypi-package-compromised-through-github-actions-cache-poisoning&lt;/a>&lt;/li>
&lt;li>arXiv, &lt;em>Weight Space Detection of Backdoors in LoRA Adapters&lt;/em> — &lt;a href="https://arxiv.org/html/2602.15195v3">https://arxiv.org/html/2602.15195v3&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>