<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>DevOps on Cloudy Mountains</title><link>https://cloudymountains.cloud/tags/devops/</link><description>Recent content in DevOps on Cloudy Mountains</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 01 Nov 2026 23:30:23 +0200</lastBuildDate><atom:link href="https://cloudymountains.cloud/tags/devops/index.xml" rel="self" type="application/rss+xml"/><item><title>Your AI Agent Is a Contractor. Treat It Like One.</title><link>https://cloudymountains.cloud/projects/platform-engineering/agents-are-contractors/</link><pubDate>Tue, 22 Sep 2026 10:00:00 +0100</pubDate><guid>https://cloudymountains.cloud/projects/platform-engineering/agents-are-contractors/</guid><description>&lt;p>For a big part of my career I was the contractor. Consultancy after consultancy, client after client. And one thing kept surprising me: the team that was supposed to help us was often the least helpful group in the building.&lt;/p>
&lt;p>Access requests took weeks. Questions got one-line answers, if any. In meetings we were the outsiders who didn&amp;rsquo;t know how things worked here, the ones who would break something, the expensive people who needed everything explained twice. Sometimes it was subtle. Sometimes it was not subtle at all.&lt;/p></description></item><item><title>The AI-Native Internal Developer Platform</title><link>https://cloudymountains.cloud/projects/platform-engineering/ai-native-idp/</link><pubDate>Tue, 26 May 2026 10:00:00 +0100</pubDate><guid>https://cloudymountains.cloud/projects/platform-engineering/ai-native-idp/</guid><description>&lt;p>Internal Developer Platforms have a well-known dirty secret: most developers do not use them. The platform team builds something genuinely useful — curated pipelines, Terraform modules, Helm charts, GitOps patterns, cost guardrails — wraps it in a service catalogue, adds a web portal, writes runbooks, and waits. Adoption trickles in, usually driven by mandate rather than enthusiasm.&lt;/p>
&lt;p>This is not a technology problem. It is a distribution problem. The platform team solved the right problem and delivered it to the wrong address.&lt;/p></description></item><item><title>Testing Terraform Plans with OPA and Conftest (and Atlantis)</title><link>https://cloudymountains.cloud/projects/policy-as-code/policy-as-code-opa-terraform/</link><pubDate>Thu, 15 May 2025 23:58:44 +0100</pubDate><guid>https://cloudymountains.cloud/projects/policy-as-code/policy-as-code-opa-terraform/</guid><description>&lt;p>As I mentioned in my &lt;a href="https://cloudymountains.cloud/projects/policy-as-code/intro-opa-terraform/">previous blog post&lt;/a>, my first OPA policy was just to catch one simple parameter, if we have in the S3 Terrafom module set the &lt;code>force_destroy = true&lt;/code>.&lt;/p>
&lt;p>Here&amp;rsquo;s a simple OPA policy that will catch this dangerous configuration:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rego" data-lang="rego">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">package&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">terraform&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">plan&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">deny&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">msg&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &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="c"># Find all resources in the plan&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="nx">resource&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">:=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">input&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">resource_changes&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">_&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Check if it&amp;#39;s an S3 bucket&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="nx">resource&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">type&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;aws_s3_bucket&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Look for force_destroy in the configuration&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="nx">resource&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">change&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">after&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">force_destroy&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">==&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&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>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nx">msg&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">:=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nf">sprintf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;S3 bucket &amp;#39;%s&amp;#39; has force_destroy set to true. This is dangerous as it allows bucket deletion even when not empty.&amp;#34;&lt;/span>&lt;span class="o">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">resource&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="nx">address&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="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This policy works by:&lt;/p></description></item><item><title>How I Learned the Hard Way That Terraform Needs Policy as Code</title><link>https://cloudymountains.cloud/projects/policy-as-code/intro-opa-terraform/</link><pubDate>Sun, 30 Mar 2025 13:00:44 +0100</pubDate><guid>https://cloudymountains.cloud/projects/policy-as-code/intro-opa-terraform/</guid><description>&lt;p>&lt;strong>At a glance&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Context:&lt;/strong> a cloud consultancy engagement, bootstrapping 15 new AWS accounts for a client with Terraform 0.11/0.12.&lt;/li>
&lt;li>&lt;strong>Incident:&lt;/strong> I accidentally deleted the S3 bucket that held the Terraform state for all 15 accounts.&lt;/li>
&lt;li>&lt;strong>Cost:&lt;/strong> all 15 accounts were recreated and provisioned again from scratch. Because everything was code, that took less than two days. The real cost was our reputation with the client.&lt;/li>
&lt;li>&lt;strong>Fix:&lt;/strong> policy as code. OPA policies evaluated against every &lt;code>terraform plan&lt;/code> in CI, failing the pipeline before a dangerous change reaches &lt;code>apply&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Outcome:&lt;/strong> 15 workload pipelines gated, and every pipeline created after them inherited the same checks.&lt;/li>
&lt;/ul>
&lt;h2 id="what-went-wrong">What went wrong?&lt;/h2>
&lt;p>A few years ago, while working for a cloud consultancy company, I made a mistake that I will never forget. I accidentally deleted a Terraform state bucket: the S3 bucket that stored the state for bootstrapping 15 AWS accounts, each packed with resources. To make things worse, it belonged to a very tough client.&lt;/p></description></item></channel></rss>