<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>OPA on My personal blog</title>
        <link>https://www.matteobianchi.eu/tags/opa/</link>
        <description>Recent content in OPA on My personal blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Tue, 23 Jun 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://www.matteobianchi.eu/tags/opa/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Policy as code nella pipeline</title>
        <link>https://www.matteobianchi.eu/p/policy-as-code-pipeline/</link>
        <pubDate>Tue, 23 Jun 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/policy-as-code-pipeline/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/policy-as-code-pipeline/cover.png" alt="Featured image of post Policy as code nella pipeline" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;Lo &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/iac-security/&#34; &gt;scanning dell&amp;rsquo;IaC&lt;/a&gt; applica regole &lt;em&gt;predefinite&lt;/em&gt;. Ma ogni
organizzazione ha regole &lt;em&gt;proprie&lt;/em&gt;: &amp;ldquo;solo immagini da registry approvati&amp;rdquo;, &amp;ldquo;ogni risorsa deve avere un
tag owner&amp;rdquo;, &amp;ldquo;niente security group aperti al mondo in produzione&amp;rdquo;. Scritte in una wiki, queste regole
non si applicano da sole: si violano per distrazione o per fretta. Il &lt;strong&gt;policy as code&lt;/strong&gt; le trasforma
in codice versionato, testabile e applicato automaticamente. È il tema generale di cui avevamo già
parlato con &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/policy-as-code-con-opa/&#34; &gt;OPA&lt;/a&gt;; qui lo mettiamo al lavoro nella
pipeline.&lt;/p&gt;
&lt;h2 id=&#34;il-pattern-pdppep-di-nuovo&#34;&gt;Il pattern PDP/PEP, di nuovo
&lt;/h2&gt;&lt;p&gt;Il policy as code è lo stesso schema &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/pdp-pep-il-motore-delle-policy/&#34; &gt;PDP/PEP&lt;/a&gt;
dello Zero Trust, applicato agli artefatti e alle configurazioni invece che agli accessi di rete:&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;
  flowchart LR
    CI[Step pipeline&amp;lt;br/&amp;gt;PEP] --&amp;gt;|&amp;#34;questo manifest/&amp;lt;br/&amp;gt;immagine è conforme?&amp;#34;| OPA[OPA&amp;lt;br/&amp;gt;PDP]
    POL[(Policy in Rego&amp;lt;br/&amp;gt;versionate in git)] --&amp;gt; OPA
    OPA --&amp;gt;|consenti / nega&amp;lt;br/&amp;gt;+ motivazione| CI
    CI --&amp;gt;|se nega| STOP[Build fallita&amp;lt;br/&amp;gt;con messaggio chiaro]
    style OPA fill:#fde2e4,stroke:#e63946
&lt;/pre&gt;

&lt;p&gt;La pipeline è il &lt;strong&gt;PEP&lt;/strong&gt; (chiede e applica); OPA è il &lt;strong&gt;PDP&lt;/strong&gt; (decide in base alle policy). Le policy
vivono in git: revisionate con pull request, testate, con una history di chi le ha cambiate e perché.&lt;/p&gt;
&lt;h2 id=&#34;rego-la-regola-come-codice&#34;&gt;Rego: la regola come codice
&lt;/h2&gt;&lt;p&gt;OPA usa &lt;strong&gt;Rego&lt;/strong&gt;, un linguaggio dichiarativo. Una policy nega finché una condizione non è soddisfatta:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rego&#34; data-lang=&#34;rego&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pipeline&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# nega qualunque immagine non firmata o da registry non approvato&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deny&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;signed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;immagine %v non firmata&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Il risultato non è un booleano muto ma un &lt;strong&gt;messaggio azionabile&lt;/strong&gt;: lo sviluppatore legge &lt;em&gt;perché&lt;/em&gt; la
build è fallita e &lt;em&gt;come&lt;/em&gt; rimediare. Questo distingue un guardrail utile da un cancello frustrante.&lt;/p&gt;
&lt;h2 id=&#34;cosa-si-esprime-come-policy&#34;&gt;Cosa si esprime come policy
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sugli artefatti&lt;/strong&gt;: solo immagini firmate (&lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/firma-artefatti-sigstore/&#34; &gt;Sigstore&lt;/a&gt;),
con SBOM presente, senza CVE critici, da basi approvate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sui manifest Kubernetes&lt;/strong&gt;: niente container privilegiati, niente &lt;code&gt;latest&lt;/code&gt;, limiti di risorse
obbligatori, nessun segreto in chiaro.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sull&amp;rsquo;IaC&lt;/strong&gt;: le regole su misura che lo scanner generico non conosce (le &lt;em&gt;tue&lt;/em&gt; convenzioni di tag,
di naming, di rete).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Strumenti come &lt;strong&gt;Conftest&lt;/strong&gt; valutano file di configurazione (YAML, JSON, HCL, Dockerfile) contro
policy Rego direttamente in pipeline, con un comando.&lt;/p&gt;
&lt;h2 id=&#34;testare-le-policy&#34;&gt;Testare le policy
&lt;/h2&gt;&lt;p&gt;Il vantaggio decisivo del policy as code è che le policy stesse sono &lt;em&gt;testabili&lt;/em&gt;. Si scrivono casi —
&amp;ldquo;questo manifest deve passare&amp;rdquo;, &amp;ldquo;quest&amp;rsquo;altro deve essere rifiutato&amp;rdquo; — e si eseguono in CI. Una policy
senza test è fragile quanto codice senza test: può diventare troppo permissiva senza che nessuno se ne
accorga.&lt;/p&gt;
&lt;h2 id=&#34;un-motore-molti-punti-di-applicazione&#34;&gt;Un motore, molti punti di applicazione
&lt;/h2&gt;&lt;p&gt;La stessa policy (&amp;ldquo;solo immagini firmate&amp;rdquo;) può valere nella pipeline &lt;em&gt;e&lt;/em&gt; all&amp;rsquo;ingresso del cluster via
&lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/admission-control/&#34; &gt;admission control&lt;/a&gt;. Un solo linguaggio, un solo repository di
regole, più punti di enforcement: è la coerenza che rende governabile la sicurezza su scala, invece di
regole scollegate ripetute in dieci posti.&lt;/p&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; se la policy as code può bloccare le build, chi impedisce che una regola troppo severa (o un bug in una policy) fermi tutti i deploy dell&#39;azienda?&lt;/summary&gt;
&lt;p&gt;È un rischio concreto — una policy è codice con potere di veto sulla consegna — e si gestisce con le
stesse pratiche che rendono sicuro qualunque altro codice critico, più alcune specifiche. Primo: le policy
si trattano come software, non come configurazione sacra. Vivono in git, passano da pull request con
revisione, e hanno &lt;em&gt;test propri&lt;/em&gt;: casi che devono passare e casi che devono essere rifiutati,
eseguiti in CI a ogni modifica della policy stessa. Una regola troppo severa si manifesta come un test
rosso prima di arrivare in produzione, esattamente come una regressione in un servizio. Secondo: le policy
si rilasciano in modo graduale. Una regola nuova parte in modalità &lt;em&gt;warn&lt;/em&gt; (segnala ma non blocca),
si osserva quanto e cosa catturerebbe sui deploy reali per un periodo, e solo quando i falsi positivi sono
sotto controllo si promuove a &lt;em&gt;enforce&lt;/em&gt;. Questo evita il blocco a sorpresa dell&#39;intera azienda al
primo giorno. Terzo: serve una via di emergenza esplicita e tracciata — un meccanismo di eccezione o di
break-glass che permetta, con approvazione e audit, di scavalcare una policy quando è palesemente lei a
sbagliare durante un incidente, invece di lasciare l&#39;unica scelta tra &#34;bloccati tutti&#34; e &#34;disattiviamo
tutto&#34;. Quarto, la scelta del comportamento di default per fase: in pipeline spesso conviene fail-closed
sulle regole di sicurezza critiche (meglio una build bloccata che un&#39;immagine non firmata in produzione),
ma la decisione va presa consapevolmente regola per regola, non subita. Il punto di fondo: il potere di
bloccare è esattamente ciò che rende la policy utile — una regola che non può fermare nulla non è un
controllo, è un suggerimento — quindi la risposta non è togliere il potere, è circondarlo di test, rollout
graduale e vie di fuga, come si fa con ogni cosa che può rompere la produzione.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;Il policy as code trasforma le regole dell&amp;rsquo;organizzazione in codice versionato, testato e applicato:
lo schema PDP/PEP portato nella pipeline, con messaggi azionabili e un solo repository di regole per
più punti di enforcement. Abbiamo blindato codice, artefatti e pipeline. Ora quegli artefatti devono
girare, e il primo è quasi sempre un container: la sicurezza delle immagini, prossimo capitolo.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
