<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>nunogrl.com - change-management</title><link href="https://nunogrl.com/" rel="alternate"></link><link href="https://nunogrl.com/categories/change-management/atom.xml" rel="self"></link><id>https://nunogrl.com/</id><updated>2024-03-21T00:00:00+00:00</updated><entry><title>Change Sets with Sceptre: Controlled AWS Changes in ITIL Environments</title><link href="https://nunogrl.com/articles/change-sets-sceptre-itil-environments/" rel="alternate"></link><published>2024-03-21T00:00:00+00:00</published><updated>2024-03-21T00:00:00+00:00</updated><author><name>Nuno Leitao</name></author><id>tag:nunogrl.com,2024-03-21:/articles/change-sets-sceptre-itil-environments/</id><summary type="html">&lt;p class="first last"&gt;Learn how to implement controlled AWS infrastructure changes in ITIL-governed environments using Sceptre and CloudFormation Change Sets&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="problem-solution"&gt;
&lt;h2&gt;🚀 Problem &amp;amp; Solution&lt;/h2&gt;
&lt;p&gt;📌 &lt;strong&gt;Context / Backstory&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We needed to &lt;strong&gt;add a stop-instance Lambda&lt;/strong&gt; to our existing AWS stack — but in a production environment governed by &lt;strong&gt;ITIL change control&lt;/strong&gt;. That meant:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;No untracked infrastructure changes&lt;/li&gt;
&lt;li&gt;No direct &amp;quot;deploy and hope&amp;quot; workflows&lt;/li&gt;
&lt;li&gt;Every change needed visibility, approval, and a rollback path&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚠️ &lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CloudFormation makes changes declarative — but deployments are immediate by default. In an ITIL environment, we needed:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A &lt;strong&gt;way to preview the change&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;record of the proposed change&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;controlled execution&lt;/strong&gt;, ideally during a change window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;💡 &lt;strong&gt;The Solution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We used &lt;strong&gt;Sceptre's built-in support for CloudFormation Change Sets&lt;/strong&gt; to decouple &lt;strong&gt;proposing changes&lt;/strong&gt; from &lt;strong&gt;executing them&lt;/strong&gt;. This gave us:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Change Set visibility before applying&lt;/li&gt;
&lt;li&gt;A file-based workflow for review and audit&lt;/li&gt;
&lt;li&gt;Controlled deployments aligned with ITIL practices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👥 &lt;strong&gt;Who This Helps&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Engineers working in &lt;strong&gt;regulated environments&lt;/strong&gt; (finance, enterprise IT, healthcare)&lt;/li&gt;
&lt;li&gt;DevOps teams needing &lt;strong&gt;pre-deployment approvals&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Anyone trying to bridge &lt;strong&gt;automation with change control&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="technical-implementation"&gt;
&lt;h2&gt;⚙️ Technical Implementation&lt;/h2&gt;
&lt;p&gt;Let's visualize the change management workflow:&lt;/p&gt;
&lt;div class="mermaid" id="mermaid-diagram-5177609105324768930"&gt;
flowchart TD
   G[Git Repo] --&gt;|Template Changes| S[Sceptre]
   S --&gt;|Create| CS[Change Set]
   CS --&gt;|Review| A[Approval]
   A --&gt;|Execute| CF[CloudFormation]
   CF --&gt;|Update| I[Infrastructure]

   subgraph "Change Control Process"
   CS
   A
   end

   subgraph "AWS"
   CF
   I
   end&lt;/div&gt;&lt;div class="section" id="add-a-stop-lambda-to-your-cloudformation-template"&gt;
&lt;h3&gt;1️⃣ Add a Stop-Lambda to Your CloudFormation Template&lt;/h3&gt;
&lt;p&gt;For example, we extended our template with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;StopInstanceLambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;AWS::Lambda::Function&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;index.handler&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!GetAtt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;LambdaExecutionRole.Arn&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;python3.9&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;30&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;ZipFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;import boto3&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;import os&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;def handler(event, context):&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;ec2 = boto3.client(&amp;#39;ec2&amp;#39;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="no"&gt;ec2.stop_instances(InstanceIds=[os.environ[&amp;#39;INSTANCE_ID&amp;#39;]])&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;Variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;INSTANCE_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!Ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;InstanceId&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We committed this change to Git but &lt;strong&gt;did not deploy yet&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="preview-with-sceptre-change-set"&gt;
&lt;h3&gt;2️⃣ Preview with Sceptre Change Set&lt;/h3&gt;
&lt;p&gt;In your Sceptre stack config (&lt;cite&gt;stop-tests.yaml&lt;/cite&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;template_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;start-stop-template.yaml&lt;/span&gt;
&lt;span class="nt"&gt;stack_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;start-tests-scheduler&lt;/span&gt;
&lt;span class="nt"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;InstanceId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;i-0123456789abcdef0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sceptre&lt;span class="w"&gt; &lt;/span&gt;create-change-set&lt;span class="w"&gt; &lt;/span&gt;dev/stop-tests.yaml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This creates a &lt;strong&gt;named Change Set&lt;/strong&gt; in CloudFormation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="review-the-change-set"&gt;
&lt;h3&gt;3️⃣ Review the Change Set&lt;/h3&gt;
&lt;p&gt;You can now inspect the proposed changes via:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sceptre&lt;span class="w"&gt; &lt;/span&gt;describe-change-set&lt;span class="w"&gt; &lt;/span&gt;dev/stop-tests.yaml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This outputs a diff-like summary of added/removed/modified resources.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="execute-the-change-set-in-a-controlled-window"&gt;
&lt;h3&gt;4️⃣ Execute the Change Set in a Controlled Window&lt;/h3&gt;
&lt;p&gt;Once approved:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;sceptre&lt;span class="w"&gt; &lt;/span&gt;execute-change-set&lt;span class="w"&gt; &lt;/span&gt;dev/stop-tests.yaml
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This &lt;strong&gt;applies only what was reviewed and approved&lt;/strong&gt;, nothing more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="troubleshooting-debugging"&gt;
&lt;h2&gt;🛠️ Troubleshooting &amp;amp; Debugging&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Change Sets fail if resources are renamed instead of replaced — use &lt;cite&gt;Retain&lt;/cite&gt; policies or snapshots carefully.&lt;/li&gt;
&lt;li&gt;If nothing appears in the Change Set, verify your stack is actually different from the current state.&lt;/li&gt;
&lt;li&gt;Include &lt;cite&gt;--no-execute-changeset&lt;/cite&gt; in manual &lt;cite&gt;aws cloudformation&lt;/cite&gt; calls if testing outside Sceptre.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="itil-alignment-best-practices"&gt;
&lt;h2&gt;🔁 ITIL Alignment &amp;amp; Best Practices&lt;/h2&gt;
&lt;p&gt;Why this works for &lt;strong&gt;change management&lt;/strong&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;✅ &lt;strong&gt;Pre-approved changes&lt;/strong&gt;: Reviewable before execution&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Audit trail&lt;/strong&gt;: Change Set IDs + Git commits form a traceable chain&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Rollback-ready&lt;/strong&gt;: No impact until applied; easy to cancel&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Automatable&lt;/strong&gt;: Integrates with GitOps, CI/CD, and approval gates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compare to a traditional ITIL CAB process:
- Sceptre's Change Set becomes the &lt;strong&gt;RFC payload&lt;/strong&gt;
- Execution timing maps to &lt;strong&gt;change windows&lt;/strong&gt;
- Logs &amp;amp; ChangeSet name tie into &lt;strong&gt;CMDB or ticketing systems&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion-takeaways"&gt;
&lt;h2&gt;✅ Conclusion &amp;amp; Takeaways&lt;/h2&gt;
&lt;p&gt;By using Sceptre's Change Sets, we introduced &lt;strong&gt;governed change control&lt;/strong&gt; without sacrificing automation. It's a clean way to blend &lt;strong&gt;DevOps practices&lt;/strong&gt; with &lt;strong&gt;ITIL compliance&lt;/strong&gt; — reducing risk while maintaining velocity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="comments-next-steps"&gt;
&lt;h2&gt;💬 Comments &amp;amp; Next Steps&lt;/h2&gt;
&lt;p&gt;Have you implemented similar change control processes in your AWS infrastructure? Share your experience or ask questions below!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Cloud"></category><category term="aws"></category><category term="sceptre"></category><category term="itil"></category><category term="change-management"></category><category term="cloudformation"></category><category term="devops"></category><category term="compliance"></category><category term="infrastructure"></category></entry></feed>