<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vladimir Sokolenko</title>
    <description>The latest articles on DEV Community by Vladimir Sokolenko (@4sokol).</description>
    <link>https://dev.to/4sokol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2976393%2F66d6ea3c-3d8a-4aeb-87ba-f9a0c59443d8.png</url>
      <title>DEV Community: Vladimir Sokolenko</title>
      <link>https://dev.to/4sokol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/4sokol"/>
    <language>en</language>
    <item>
      <title>From Podman to Production: Building Trusted Container Images with Konflux</title>
      <dc:creator>Vladimir Sokolenko</dc:creator>
      <pubDate>Thu, 29 Oct 2026 16:42:41 +0000</pubDate>
      <link>https://dev.to/4sokol/from-podman-to-production-building-trusted-container-images-with-konflux-1lgn</link>
      <guid>https://dev.to/4sokol/from-podman-to-production-building-trusted-container-images-with-konflux-1lgn</guid>
      <description>&lt;p&gt;I work at Red Hat as a Senior SRE on the Konflux Infra team. We are responsible for the infrastructure around Konflux CI, the build system Red Hat has been developing: the clusters it runs on, the Terraform behind them, backups and disaster recovery, new releases, all the plumbing that has to keep working so that the teams building products on top of it never have to think about it.&lt;/p&gt;

&lt;p&gt;Konflux itself is the part that probably needs introducing, because outside Red Hat it is still not widely known. It is an open source, Kubernetes native build system. Kubernetes native in a fairly literal sense: pipelines are custom resources living on a cluster, scheduled as Pods, with no separate build server standing next to them. What sets it apart from a general purpose pipeline runner is that it is built around supply chain security. Builds run with the network cut off, images are signed, an SBOM and SLSA provenance come out the other end, and a policy gate decides whether the result is allowed to be released at all. None of that is something you switch on. It is the default behaviour.&lt;/p&gt;

&lt;p&gt;Here is the thing though. Running the infrastructure under a tool and actually using that tool are two different jobs. I knew Konflux well from the cluster side and much less well from the side of someone who just wants to ship a container image. So I decided to build something with it myself, start to finish, the way any user would, mostly to understand it properly.&lt;/p&gt;

&lt;p&gt;In June 2026 &lt;a href="https://www.youtube.com/watch?v=J1g38v1P7q0" rel="noopener noreferrer"&gt;I gave a presentation at DevConf.CZ in Brno&lt;/a&gt; called "From Podman to Production", based on exactly that. The idea was simple: take one Containerfile, build it twice, using podman on my local and then using Konflux CI, and look at what you can actually prove about each result.&lt;/p&gt;

&lt;p&gt;A few people asked me afterwards to write it up, so here it is. The structure follows the talk pretty closely, screenshots and all.&lt;/p&gt;

&lt;p&gt;The whole thing is built around one rule I kept repeating on stage: the Containerfile never changes. Not one line. What changes is everything around it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqkih9ri6ko9942urqm4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqkih9ri6ko9942urqm4.png" alt="One Containerfile, three acts: local Podman build, Konflux trusted pipeline, verify and run" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo app
&lt;/h2&gt;

&lt;p&gt;I wanted something that wasn't a hello world, so the demo app is a small Flask API that talks to the Pretalx instance behind DevConf.CZ. It pulls the real conference schedule: how many talks there are, the breakdown by session type, the room list.&lt;/p&gt;

&lt;p&gt;It also has a &lt;code&gt;/api/self&lt;/code&gt; endpoint that searches the schedule for the talk I was giving at that moment. So during the presentation the app was literally looking itself up in the conference system. That got a laugh, which is about all you can ask for from a demo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjgcz3wh9vkq8j65zinsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjgcz3wh9vkq8j65zinsb.png" alt="Flask app on port 8080 pulling from the Pretalx API and exposing /api/stats, /api/rooms, /api/types and /api/self" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 1: the build everybody already knows
&lt;/h2&gt;

&lt;p&gt;Here is the Containerfile. Nothing clever about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; registry.fedoraproject.org/fedora:44&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3-pip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dnf clean all
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; app/ /opt/app/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; /opt/app/requirements.txt

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "/opt/app/main.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;podman build &lt;span class="nt"&gt;-t&lt;/span&gt; devconf-api:latest &lt;span class="nb"&gt;.&lt;/span&gt;
podman run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 devconf-api:latest
curl &lt;span class="nt"&gt;-4&lt;/span&gt; localhost:8080/api/stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three commands and you have a working API serving live conference data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fda1xnlah4gcyohuss4hd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fda1xnlah4gcyohuss4hd.gif" alt="Terminal recording of podman build, podman run and curl against the local API" width="600" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podman is rootless, daemonless, OCI native. For the inner development loop this is as good as it gets. Fast feedback, no infrastructure, no waiting on a queue.&lt;/p&gt;

&lt;p&gt;And for development that is genuinely fine. The problem starts when somebody asks you to ship it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you cannot prove
&lt;/h2&gt;

&lt;p&gt;Picture a security review of that image. Can you prove which source commit produced it? No. Is it signed? No. Do you have an SBOM listing every dependency inside? No. Was the build isolated from the network? Definitely not, your laptop had full internet access the whole time. Did anything scan it? No. Was there a gate that could have stopped a bad build from being released? No.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0f2m1xo6qy42gpd0vbgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0f2m1xo6qy42gpd0vbgx.png" alt="Local build versus production ready: no provenance, no signature, no SBOM, open network, no scan, no policy gate on the left; SLSA provenance, cosign signature, SPDX SBOM, hermetic build, Clair and ClamAV, Enterprise Contract on the right" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of this means the image is bad. It means you have no evidence either way, and in a supply chain "trust me" is not evidence.&lt;/p&gt;

&lt;p&gt;So the question for the rest of the talk was: can I keep this exact Containerfile and get all of that metadata without writing any of it myself?&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 2: what Konflux actually is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://konflux-ci.dev/" rel="noopener noreferrer"&gt;Konflux&lt;/a&gt; is an open source, Kubernetes native trusted software factory. The important word in that sentence is trusted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faca3ep4cb9w0ghni29cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faca3ep4cb9w0ghni29cq.png" alt="Konflux logo" width="600" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stack is all CNCF and upstream pieces:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pipelines&lt;/td&gt;
&lt;td&gt;Tekton (Kubernetes CRDs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Builds&lt;/td&gt;
&lt;td&gt;Buildah (the same engine Podman uses)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing&lt;/td&gt;
&lt;td&gt;Sigstore / cosign, keyless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scanning&lt;/td&gt;
&lt;td&gt;Clair for CVEs, ClamAV for malware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy&lt;/td&gt;
&lt;td&gt;Conforma (Enterprise Contract)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provenance&lt;/td&gt;
&lt;td&gt;in-toto, SLSA Level 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;Hermeto for hermetic prefetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Registry&lt;/td&gt;
&lt;td&gt;Quay, with OCI artifacts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice Buildah in there. That is the same build engine Podman shells out to, which is exactly why the Containerfile does not need to change. You are not learning a new build system, you are wrapping the one you already use in a lot of machinery.&lt;/p&gt;

&lt;p&gt;The pieces you will see by name later are PipelineRun and TaskRun. Those are the Tekton custom resources a build turns into once it is running on the cluster, and you query them with &lt;code&gt;oc get&lt;/code&gt; like anything else.&lt;/p&gt;

&lt;p&gt;It runs on OpenShift, ROSA, EKS or plain Kubernetes, and it is Apache 2.0 across over 150 repositories on GitHub. &lt;/p&gt;

&lt;p&gt;It is also not only a Red Hat thing. Fedora runs its own Konflux instance and has been moving real work onto it: Fedora CoreOS has an &lt;a href="https://fedoraproject.org/wiki/Changes/Build_FCOS_on_Fedora_Konflux" rel="noopener noreferrer"&gt;accepted Change for Fedora 44&lt;/a&gt; to build the stable, testing and next streams there, and the reason given at the top of that page is getting SBOMs and attestations into the hands of end users. Same motivation as this article, at distribution scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need before you start
&lt;/h2&gt;

&lt;p&gt;Three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Kubernetes cluster. I used OpenShift for the demo.&lt;/li&gt;
&lt;li&gt;A Konflux instance running on it.&lt;/li&gt;
&lt;li&gt;A Git integration. On GitHub that is a GitHub App, which is what enables Pipelines as Code. On GitLab you use a webhook plus an access token instead.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63l3wgyxluhlp4tz0ovd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63l3wgyxluhlp4tz0ovd.gif" alt="Konflux Staging GitHub App installation page" width="799" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Onboarding is two YAML files
&lt;/h2&gt;

&lt;p&gt;This is the part that surprises people. To put a repository under Konflux you apply two standard Kubernetes resources. Here they are in full, nothing trimmed for the article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appstudio.redhat.com/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Application&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devconf-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vsok-tenant&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DevConf Schedule API&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Application is just a logical grouping, the umbrella that everything shipped together lives under. If I had a frontend and a backend they would be two Components under the same Application. Note the namespace, &lt;code&gt;vsok-tenant&lt;/code&gt;. Konflux gives every tenant their own namespace and that is where all of this lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appstudio.redhat.com/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Component&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devconf-api&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vsok-tenant&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devconf-api&lt;/span&gt;
  &lt;span class="na"&gt;componentName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devconf-api&lt;/span&gt;
  &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/vsokolen-redhat/devconf-demo&lt;/span&gt;
      &lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the Component out loud and it is almost embarrassingly short: belongs to this Application, lives in this Git repo, build this branch. There is no build configuration in it at all. No base image, no build steps, no mention of the Containerfile, no registry credentials. Konflux works the rest out by itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;oc apply &lt;span class="nt"&gt;-f&lt;/span&gt; application.yaml
oc apply &lt;span class="nt"&gt;-f&lt;/span&gt; component.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The moment the Component lands on the cluster, several controllers wake up. The Build Service finds the Containerfile. The Image Controller provisions a Quay repository for the output. Pipelines as Code opens a pull request on my repo containing a &lt;code&gt;.tekton/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;I did not write that pipeline. Konflux wrote it for me and put it in my repository, next to the Containerfile, as code I can read and edit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh5d8ql5wqt7wgs7opa6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh5d8ql5wqt7wgs7opa6f.png" alt="Pull request opened by the konflux-staging bot on the devconf-demo repo, titled &amp;quot;Pipelines as Code configuration proposal&amp;quot;, all checks passed" width="800" height="919"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside are two files: &lt;code&gt;on-push.yaml&lt;/code&gt;, which builds when something merges to main, and &lt;code&gt;on-pull-request.yaml&lt;/code&gt;, which builds every PR. Each one is a PipelineRun manifest with a CEL expression deciding when it fires.&lt;/p&gt;

&lt;p&gt;I reviewed it, merged it, and that merge triggered the first real build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbsdv173rsogcl6n4yt8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbsdv173rsogcl6n4yt8j.png" alt="Konflux UI showing the DevConf Schedule API application activity, both pipeline runs succeeded" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the same thing from the terminal, which is where I spend most of my time anyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjpqmr7uw90qupzf5ktyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjpqmr7uw90qupzf5ktyu.png" alt="oc get pipelineruns and oc get taskruns showing init, clone-repository, prefetch-dependencies succeeded and build-container running" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Worth walking through the tasks, because this is where the trust actually gets built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;init and clone-repository.&lt;/strong&gt; Nothing exciting, a git clone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;prefetch-dependencies.&lt;/strong&gt; This is Hermeto. It resolves and downloads every pip package the app needs, with network access, and generates a complete SBOM while it does it. Every dependency gets captured here and nowhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build-container.&lt;/strong&gt; The interesting one. Buildah runs with &lt;code&gt;--network=none&lt;/code&gt;. The network is physically cut for the duration of the build. The only things available are what Hermeto already fetched. The analogy I used on stage was locking the chef in the kitchen with only the ingredients you approved, and no delivery door.&lt;/p&gt;

&lt;p&gt;That is what a hermetic build means in practice, and it is also why the SBOM is trustworthy. Nothing can sneak in halfway through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CVE scan and malware scan.&lt;/strong&gt; Clair and ClamAV, automatically. No plugin to install, no config to write.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing and push.&lt;/strong&gt; Tekton Chains watches every build in the cluster. When one completes it signs the image with cosign using keyless signing, generates SLSA Level 3 provenance, and attaches both to the image in Quay. Chains signs the image, the provenance attestation and the SBOM separately, so each one is independently verifiable.&lt;/p&gt;

&lt;p&gt;All of that happened without me configuring a single thing beyond those two YAML files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate
&lt;/h2&gt;

&lt;p&gt;When the build finishes, Konflux creates a Snapshot: an immutable record of every component image at its exact SHA256 digest. Not a tag. A digest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0yph9vqug62wr6yggnz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0yph9vqug62wr6yggnz.png" alt="Konflux Snapshots tab listing two snapshots for devconf-api, with oc get snapshots in a terminal below" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then the Enterprise Contract runs. This is the policy gate, the bouncer at the door. It asks whether the image is signed, whether it has provenance, whether the build was hermetic, whether the CVE scan passed, whether the base image is still supported.&lt;/p&gt;

&lt;p&gt;If any check fails, the release is blocked. There is no override flag, which is the entire point. A gate you can skip when you are in a hurry is not a gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Act 3: verifying it myself
&lt;/h2&gt;

&lt;p&gt;Policy gates are nice, but I wanted to show the audience the evidence directly rather than ask them to take the UI's word for it. One command does that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cosign tree quay.io/redhat-user-workloads-stage/vsok-tenant/devconf-api@sha256:ce0df74bba3fbfabc6469d931c774c0270f809edcf82bf658bee533cd35e0f77
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrjc6m04039r2cpw18fo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkrjc6m04039r2cpw18fo.png" alt="cosign tree output listing attestations, three signatures, SBOM, Clair report, ClamAV report and two SARIF reports attached to the image" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything hanging off that single image reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three cosign signatures&lt;/li&gt;
&lt;li&gt;An attestation holding SLSA Level 3 provenance&lt;/li&gt;
&lt;li&gt;A full SBOM&lt;/li&gt;
&lt;li&gt;A Clair CVE report&lt;/li&gt;
&lt;li&gt;A ClamAV malware report&lt;/li&gt;
&lt;li&gt;Two SARIF reports from static analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six kinds of supply chain artifact, attached to one container image, none of which I asked for explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it
&lt;/h2&gt;

&lt;p&gt;The last step of the demo was pulling the image back down and running it, the same way I ran the local build at the start. Not by tag, by digest, so I know it is exactly the image that was signed and attested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6fymrjm21s580n7tsvug.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6fymrjm21s580n7tsvug.gif" alt="podman pull by digest, podman run and curl returning the same DevConf stats from the trusted image" width="760" height="928"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same output. Same conference data. Same app.&lt;/p&gt;

&lt;p&gt;That is the whole point, and it is worth being blunt about it: the difference is not what the app does. The difference is what you can prove about how it was built.&lt;/p&gt;

&lt;p&gt;Go back to that list of questions from the start. Which source commit built this? The provenance says so. What is inside it? The SBOM says so. Was it isolated during the build? The provenance records the hermetic flag. Did anything scan it? Two reports say yes. Is it signed? Three signatures say yes. And none of those answers came from me writing pipeline code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five things to take away
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2hsrk0502kfpfrydrqmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2hsrk0502kfpfrydrqmw.png" alt="Five takeaways: start with Podman, hermetic builds matter, signing is automatic, policy gates block bad releases, no custom YAML needed" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with Podman.&lt;/strong&gt; Keep your inner loop fast. Your Containerfile moves to Konflux unchanged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hermetic builds matter.&lt;/strong&gt; Cutting the network during the build is what stops a dependency from changing under you, and it is what makes the SBOM complete rather than approximate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signing is automatic.&lt;/strong&gt; Tekton Chains plus cosign, keyless, on every build. No key management, no rotation, nothing to leak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy gates block bad releases.&lt;/strong&gt; The Enterprise Contract validates provenance and scan results before anything can be released.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No custom YAML needed.&lt;/strong&gt; Konflux ships opinionated defaults. Point it at a repo, push code, get trusted images.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or, the version I ended the talk with: your laptop builds containers, Konflux builds trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;Everything here is open source under Apache 2.0.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My presentation on DevConf.cz: &lt;a href="https://www.youtube.com/watch?v=J1g38v1P7q0" rel="noopener noreferrer"&gt;youtube&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Konflux: &lt;a href="https://konflux-ci.dev" rel="noopener noreferrer"&gt;konflux-ci.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quick start: &lt;a href="https://konflux-ci.dev/docs/getting-started/" rel="noopener noreferrer"&gt;konflux-ci.dev/docs/getting-started/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/konflux-ci" rel="noopener noreferrer"&gt;github.com/konflux-ci&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenShift Local (CRC), if you want a cluster on your laptop: &lt;a href="https://developers.redhat.com/products/openshift-local" rel="noopener noreferrer"&gt;developers.redhat.com/products/openshift-local&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Podman: &lt;a href="https://podman.io" rel="noopener noreferrer"&gt;podman.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tekton: &lt;a href="https://tekton.dev" rel="noopener noreferrer"&gt;tekton.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sigstore: &lt;a href="https://sigstore.dev" rel="noopener noreferrer"&gt;sigstore.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SLSA: &lt;a href="https://slsa.dev" rel="noopener noreferrer"&gt;slsa.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Buildah: &lt;a href="https://buildah.io" rel="noopener noreferrer"&gt;buildah.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The slides from the talk are &lt;a href="https://nc.sokolenko.org/s/Kp5aGDKP34p9Tta" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy to talk about trusted pipelines, Tekton or Kubernetes native CI in general. You can find me on &lt;a href="https://www.linkedin.com/in/sokolenko/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, or just leave a comment.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
      <category>ci</category>
      <category>security</category>
    </item>
  </channel>
</rss>
