<?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>Forem: Kenaz Kwa</title>
    <description>The latest articles on Forem by Kenaz Kwa (@kenazkwa).</description>
    <link>https://forem.com/kenazkwa</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F350306%2F1098d77e-2fc6-4fb8-850d-cecf2ce37a23.jpg</url>
      <title>Forem: Kenaz Kwa</title>
      <link>https://forem.com/kenazkwa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kenazkwa"/>
    <language>en</language>
    <item>
      <title>Terminate Unused EC2 Instances with Python!</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Thu, 11 Jun 2020 22:11:42 +0000</pubDate>
      <link>https://forem.com/relay/terminate-unused-ec2-instances-with-python-3df0</link>
      <guid>https://forem.com/relay/terminate-unused-ec2-instances-with-python-3df0</guid>
      <description>&lt;h1&gt;
  
  
  Automatically terminate EC2 instances with configurable lifetimes
&lt;/h1&gt;

&lt;p&gt;This workflow looks at all of the EC2 instances in a given account and region and selects a subset of those to terminate. The termination criteria are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not tagged with a termination date or lifetime after 4 minutes&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;termination_date&lt;/code&gt; or &lt;code&gt;lifetime&lt;/code&gt; tags are present but cannot be parsed&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;termination_date&lt;/code&gt; or &lt;code&gt;lifetime&lt;/code&gt; tags indicate that the instance hasexpired&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An instance may be configured to never terminate if its &lt;code&gt;lifetime&lt;/code&gt; tag has thespecial value &lt;code&gt;indefinite&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you run this workflow, you will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account.&lt;/li&gt;
&lt;li&gt;An AWS IAM user with permissions to list and terminate EC2 instances (if notrun in dry run mode).&lt;/li&gt;
&lt;li&gt;One or more running EC2 instances that are configured to use the&lt;code&gt;termination_date&lt;/code&gt; or &lt;code&gt;lifetime&lt;/code&gt; tags.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run the workflow
&lt;/h2&gt;

&lt;p&gt;Follow these steps to run the workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add your AWS credentials as secrets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Edit&lt;/strong&gt; &amp;gt; &lt;strong&gt;Secrets&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Define new secret&lt;/strong&gt; and use the following values:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KEY&lt;/strong&gt; : &lt;code&gt;aws.accessKeyID&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VALUE&lt;/strong&gt; : Enter your AWS access key id associated with the account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KEY&lt;/strong&gt; : &lt;code&gt;aws.secretAccessKey&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VALUE&lt;/strong&gt; : Enter your AWS secret access key associated with the account

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Run workflow&lt;/strong&gt; and wait for the workflow run page to appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warning:&lt;/strong&gt; If you run the workflow with the &lt;code&gt;dryRun&lt;/code&gt; parameter set to&lt;code&gt;false&lt;/code&gt;, instances not in compliance with this workflow policy willimmediately be terminated.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Automatically running on a schedule
&lt;/h2&gt;

&lt;p&gt;Policy-driven workflows are best run on a recurring schedule. To set up aschedule trigger for this workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Edit&lt;/strong&gt; &amp;gt; &lt;strong&gt;Triggers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click &lt;strong&gt;Define new trigger&lt;/strong&gt; and use the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trigger type&lt;/strong&gt; : Schedule&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger integration&lt;/strong&gt; : System&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interval&lt;/strong&gt; : Intervals follow the &lt;a href="https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals"&gt;ISO 8601 repeatinginterval&lt;/a&gt;format. To run this workflow every 5 minutes indefinitely from now on,enter: &lt;code&gt;R/2020-01-01T00:00:00Z/PT5M&lt;/code&gt;. You can configure the interval at theend of this string to change the execution frequency.

&lt;ol&gt;
&lt;li&gt;Enter values for the parameter bindings that match your environment.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add trigger&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within the next 5 minutes, you should see the workflow run automatically for thefirst time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Secure your AWS Account by Removing Unused EC2 Key Pairs with Python</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Fri, 22 May 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/relay/secure-your-aws-account-by-removing-unused-ec2-key-pairs-with-python-34j6</link>
      <guid>https://forem.com/relay/secure-your-aws-account-by-removing-unused-ec2-key-pairs-with-python-34j6</guid>
      <description>&lt;p&gt;&lt;a href="///static/b87d95df52ffaf969dfdc95f3409529d/abd3e/1579728866437-6397f3d89ec3.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1yTurmUN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://relay.sh/static/b87d95df52ffaf969dfdc95f3409529d/4b190/1579728866437-6397f3d89ec3.jpg" alt="Photo of silver and gold door keys" title="Photo of silver and gold door keys"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloud security is top of mind right now, given the various high-profile security breaches today. One overlooked source of potential vulnerabilities is unused EC2 Key Pairs. EC2 Key Pairs are used to configure an EC2 instance with SSH access and provide a convenient way to manage instances. However, when was the last time you performed an audit to make sure that the only key pairs in your account are given to active employees who have proper authorization to connect to instances? Are you sure all of those keys are even being used?&lt;/p&gt;

&lt;p&gt;In this blog post, we’ll use a simple Python script to perform an audit of all EC2 key pairs in the account and determine which of those keys are not being used and delete them.&lt;/p&gt;

&lt;h1&gt;
  
  
  First, let’s find all the keys.
&lt;/h1&gt;

&lt;p&gt;First, we configure the &lt;a href="https://aws.amazon.com/sdk-for-python/"&gt;&lt;code&gt;boto3&lt;/code&gt;&lt;/a&gt; client to connect to our AWS account and allow us to start listing EC2 Key Pairs. We’ll also create 3 lists - one for storing all key pairs, one for used key pairs, and one for unused key pairs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3

sess = boto3.Session(
  *# TODO: Supply your AWS credentials &amp;amp; specified region here*
  aws_access_key_id=' MYAWSACCESSKEYID',
  aws_secret_access_key='MYSECRETACCESSKEY',
  region_name='us-east-1', *# Or whatever region you want*
)

# Creating lists for all, used, and unused key pairs
all_key_pairs = []
all_used_key_pairs = []
all_unused_key_pairs = []

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we make a call to get all the key pairs and filter for the key pair names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# List the key pairs in the selected region
ec2 = sess.client('ec2')
all_key_pairs = list(map(lambda i: i['KeyName'], ec2.describe_key_pairs()['KeyPairs']))

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Second, let’s find all the key pairs in use.
&lt;/h2&gt;

&lt;p&gt;In order to find all the key pairs currently in use, we first list the EC2 instances and then inspect those instances for their key pair.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Each EC2 reservation returns a group of instances.
instance_groups = list(map(lambda i: i['Instances'], ec2.describe_instances()['Reservations']))

# Create a list of all used key pairs in the account based on the running instances
for group in instance_groups:
  for i in group:
    if i['KeyName'] not in all_used_key_pairs:
      all_used_key_pairs.append(i['KeyName'])

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Next, compare the lists.
&lt;/h2&gt;

&lt;p&gt;We compare each key pair in &lt;code&gt;all_key_pairs&lt;/code&gt; to the list of used key pairs. If the key pair is not being used, we add it to the list of unused key pairs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Now compare the two lists
for key in all_key_pairs:
  if key not in all_used_key_pairs:
    all_unused_key_pairs.append(key)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Finally, we delete the unused key pairs.
&lt;/h2&gt;

&lt;p&gt;We delete the unused key pairs by iterating over the list of unused key pairs and calling the &lt;code&gt;ec2.delete_key_pair()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Delete all unused key pairs
print('Deleting unused key pairs:')
for key in all_unused_key_pairs:
  print(key)
  ec2.delete_key_pair(KeyName=key)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/kenazk/60cd3993803f4e26c917aa7a12533795"&gt;Find the whole Python script here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Deleting unused key pairs is a good practice to ensure that no one is granted unauthorized access to your instances. Want to run this workflow on a schedule? Invite other people on your team to kick off workflows? Notify your team in Slack when key pairs are deleted? That’s why we built Relay.&lt;/p&gt;

&lt;p&gt;We built this workflow out for you so you don’t have to – &lt;a href="https://relay.sh/workflows/ec2-remove-unused-key-pairs"&gt;try it out here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To learn more about the product, sign up for our updates on &lt;a href="https://relay.sh/"&gt;relay.sh&lt;/a&gt;. Our mission is to free you of tedious cloud-native workflows with event-driven automation! For more content like this, please follow our &lt;a href="https://dev.to/blog/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Delete Unattached EBS Volumes with Python</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Wed, 06 May 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/relay/delete-unattached-ebs-volumes-with-python-509p</link>
      <guid>https://forem.com/relay/delete-unattached-ebs-volumes-with-python-509p</guid>
      <description>&lt;p&gt;In our continuation of &lt;a href="https://dev.to/blog/how-to-cut-unused-ec2-instances-with-aws-lambda"&gt;ways to reduce your AWS bill&lt;/a&gt;, one source of unexpected charges are unattached and forgotten EBS volumes. While not typically the most expensive line item on the bill, all of those little volumes can add up when deploying across multiple accounts and regions.&lt;/p&gt;

&lt;p&gt;For months, I remember getting bills for nominal amounts of money due to unattached EBS volumes, going into the AWS console to delete them and take care of it, only to realize the next month I’ve forgotten one.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/f8e68eae40df6394940c3a9f8774044f/dd45a/SrmFfhiw4IL5BbR7zS5nfkpC.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VT7ro4Kk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/f8e68eae40df6394940c3a9f8774044f/dd45a/SrmFfhiw4IL5BbR7zS5nfkpC.png" alt="Example AWS bill" title="Example AWS bill"&gt;&lt;/a&gt;&lt;em&gt;My sad AWS bill&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop it before it starts - &lt;code&gt;DeleteOnTermination&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;One proactive way of ensuring that EBS volumes are deleted when your EC2 instance is terminated is by ensuring that the &lt;code&gt;DeleteOnTermination&lt;/code&gt; attribute is set to true for all volumes that you don’t want to stick around and add up.&lt;/p&gt;

&lt;p&gt;To change the &lt;code&gt;DeleteOnTermination&lt;/code&gt; attribute, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# TODO: Insert your instance id
$ aws ec2 modify-instance-attribute —instance-id i-1234567890abcdef0 —block-device-mappings file://mapping.json

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the following &lt;code&gt;mapping.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
    “DeviceName”: “/dev/sda1”,
    “Ebs”: {
      “DeleteOnTermination”: false
    }
  }
]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For more information, check out the &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/terminating-instances.html#delete-on-termination-running-instance"&gt;AWS EC2 docs&lt;/a&gt; here. By default, the root volume is already configured for &lt;code&gt;DeleteOnTermination&lt;/code&gt; to be true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a Python script to audit and delete unattached EBS volumes
&lt;/h2&gt;

&lt;p&gt;Ok, that’s great. But what about all the EBS volumes I have laying around my AWS account right now? Here’s a Python script that solves this problem in 3 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listing and describing each of your EBS volumes in a given AWS account and region&lt;/li&gt;
&lt;li&gt;Filtering the volumes for those that don’t have any attachments&lt;/li&gt;
&lt;li&gt;Deleting the unattached EBS volumes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Listing and describing EBS volumes
&lt;/h2&gt;

&lt;p&gt;First, we configure the &lt;a href="%5Bhttps://aws.amazon.com/sdk-for-python/"&gt;&lt;code&gt;boto3&lt;/code&gt;&lt;/a&gt;) client to connect to our AWS account and allow us to start listing EBS volumes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3

sess = boto3.Session(
    # TODO: Supply your AWS credentials &amp;amp; specified region here
  aws_access_key_id='MYAWSACCESSKEYID',
  aws_secret_access_key='MYSECRETACCESSKEY',
  region_name='us-east-1', # Or whatever region you want
)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, we make a call to get all EC2 volumes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ec2 = sess.resource('ec2')
volumes = ec2.volumes.all()

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will return the list of all EC2 volumes in the specified region and account. This will return a collection of EBS volume objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Filtering unattached EBS volumes
&lt;/h2&gt;

&lt;p&gt;Next, we can filter this list and add the ones that are unattached to a termination list &lt;code&gt;to_terminate&lt;/code&gt;. Check out the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;to_terminate=[]
for volume in volumes:
    print('Evaluating volume {0}'.format(volume.id))
    print('The number of attachments for this volume is {0}'.format(len(volume.attachments)))

    # Here's where you might add other business logic for deletion criteria
    if len(volume.attachments) == 0:
        to_terminate.append(volume)

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Why not just delete the volume in the same step? By decoupling the logic of filtering from the deletion logic, we can take different types of actions for volumes with different attributes.&lt;/p&gt;

&lt;p&gt;For example, we might delete all the unattached volumes, but we might want to send a Slack notification for all of the volumes that are not encrypted (out of scope for this post).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Deleting the volumes
&lt;/h2&gt;

&lt;p&gt;The deletion of the logic is simple. Each volume has a &lt;code&gt;delete()&lt;/code&gt; method to delete the volume. We check for the empty condition, then delete all the volumes that are on the termination list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if len(to_terminate) == 0:
    print ("No volumes to terminate! Exiting.")
    exit()

for volume in to_terminate:
    print('Deleting volume {0}'.format(volume.id))
    volume.delete()

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find the &lt;a href="https://gist.github.com/kenazk/bfdb23ef92bfe0db75099912c5c4547a"&gt;whole Python script here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That’s it! Want to run this workflow on a schedule? Invite other people on your team to kick off workflows? Notify your team in Slack when volumes have been deleted? That’s why we built Relay.&lt;/p&gt;

&lt;p&gt;To learn more about our mission and product, sign up for our updates on &lt;a href="https://relay.sh/"&gt;relay.sh&lt;/a&gt;. Our mission is to free you of tedious cloud-native workflows with event-driven automation! For more content like this, please follow our &lt;a href="https://dev.to/blog"&gt;blog&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Cut Unused EC2 instances with AWS Lambda</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Fri, 13 Mar 2020 17:41:30 +0000</pubDate>
      <link>https://forem.com/kenazkwa/how-to-cut-unused-ec2-instances-with-aws-lambda-5eph</link>
      <guid>https://forem.com/kenazkwa/how-to-cut-unused-ec2-instances-with-aws-lambda-5eph</guid>
      <description>&lt;p&gt;Originally posted on &lt;a href="https://medium.com/relay-sh/how-to-cut-unused-ec2-instances-with-aws-lambda-c2e78f651332"&gt;our blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Uh... Why is this month's AWS bill so high? &lt;/p&gt;

&lt;p&gt;Forgotten AWS EC2 instances have made everyone’s pockets hurt. If you don’t proactively clean up unused EC2 instances, cloud spending can quickly get out of control. However, it can be tedious to routinely check which EC2 instances are still in use, track down the old ones, and remove them. Luckily — we know how to automate these tasks!&lt;/p&gt;

&lt;p&gt;This post walks you through de-provisioning unused EC2 instances by using AWS Lambda and CloudFormation to deploy an EC2 reaper that uses simple Tags to cut down on spending.&lt;/p&gt;

&lt;p&gt;To see the full code, check out &lt;a href="https://github.com/puppetlabs/aws_resource_reaper/tree/master/lambdas/ec2"&gt;this repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS EC2 Reaper overview
&lt;/h2&gt;

&lt;p&gt;The AWS Reaper works by checking and enforcing tags that are set on the EC2 instances. All EC2 instances must be tagged with a &lt;code&gt;lifetime&lt;/code&gt; or a &lt;code&gt;termination_date&lt;/code&gt;. The &lt;code&gt;termination_date&lt;/code&gt; defines a future date after which the EC2 instance will be terminated. Alternatively, the Reaper looks for a &lt;code&gt;lifetime&lt;/code&gt; tag–if found, it calculates a new future date and adds that date as the &lt;code&gt;termination_date&lt;/code&gt; tag for the EC2 instance.&lt;/p&gt;

&lt;p&gt;First, let’s look at the &lt;code&gt;reaper.py&lt;/code&gt;. The main reaper logic for handling instances is in the &lt;code&gt;terminate_expired_instances&lt;/code&gt; function which lists instances and looks up the termination date tag for each instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s"&gt;'Name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'instance-state-name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Values'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'running'&lt;/span&gt;&lt;span class="p"&gt;]}])&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;ec2_termination_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'termination_date'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Improperly Tagged Instances
&lt;/h3&gt;

&lt;p&gt;If we find an instance that doesn’t have a &lt;code&gt;termination_date&lt;/code&gt; or we find the tag can’t be parsed, we stop it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ec2_termination_date&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No termination date found for {0}"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;stop_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"EC2 instance has no termination_date"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;improperly_tagged&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This enables us to stop the b̶l̶e̶e̶d̶i̶n̶g̶ billing while we contact the instance owner to see if it should still be kept around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expired Instances
&lt;/h3&gt;

&lt;p&gt;For all instances we find that are expired, we destroy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ec2_termination_date&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;INDEFINITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dateutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec2_termination_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;timenow_with_utc&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
       &lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dateutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ec2_termination_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;timenow_with_utc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EC2 instance will be terminated {0} seconds from now, roughly"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;terminate_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"EC2 instance is expired"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;deleted_instances&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the EC2 reaper
&lt;/h2&gt;

&lt;p&gt;Now, we could just run this python script against different AWS regions and we’d already be better off than doing this manually. However, we would rather not spend time babysitting scripts at all. We’re going to deploy this into AWS using &lt;a href="http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html"&gt;CloudFormation Stacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Deploying the AWS reaper has two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;deploy_to_s3.yaml&lt;/code&gt;&lt;/strong&gt; AWS CloudFormation template that places the lambda zip resources in S3 buckets in every region so that the deploy_reaper template can read them for Reaper deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;deploy_reaper.yaml&lt;/code&gt;&lt;/strong&gt; AWS CloudFormation template that installs the reaper creates the IAM role and deploys the lambda function to perform the instance reaping.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  deploy_to_s3 template
&lt;/h3&gt;

&lt;p&gt;In order to use this template, you must first manually create an S3 bucket that contains the resources to copy across all regions. You will need to do this once per region; S3 resources can be read between accounts but not between regions for AWS Lambda. This only needs to be done one time for the administrative account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually create an S3 bucket accessible from the administrative account. Zip up the two python reaper files, &lt;code&gt;reaper.py&lt;/code&gt; and &lt;code&gt;slack_notifier.py&lt;/code&gt; and place them in the bucket, naming them &lt;code&gt;reaper.zip&lt;/code&gt; and &lt;code&gt;slack_notifier.zip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From the administrative account, create a new stack set and use the &lt;code&gt;deploy_to_s3&lt;/code&gt; template. An example CLI invocation would look like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation create-stack-set &lt;span class="nt"&gt;--stack-set-name&lt;/span&gt; reaper-assets &lt;span class="nt"&gt;--template-body&lt;/span&gt; 
file://path/to/deploy_to_s3.yaml &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_IAM &lt;span class="nt"&gt;--parameters&lt;/span&gt;
&lt;span class="nv"&gt;ParameterKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;OriginalS3Bucket,ParameterValue&lt;span class="o"&gt;=&lt;/span&gt;reaperfiles
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy stack-set-instances for this stack set, one per region in the administrative account. Check the Amazon documentation for the most up-to-date region list. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation create-stack-instances &lt;span class="nt"&gt;--stack-set-name&lt;/span&gt; &lt;span class="nt"&gt;--accounts&lt;/span&gt; 123456789012
&lt;span class="nt"&gt;--regions&lt;/span&gt; &lt;span class="s2"&gt;"us-west-1"&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  deploy_reaper template
&lt;/h3&gt;

&lt;p&gt;After the resources for the reaper have been distributed, you can use the &lt;code&gt;deploy_reaper&lt;/code&gt; CloudFormation template to deploy the reaper into an account.&lt;/p&gt;

&lt;p&gt;You will need to follow the steps below for each account you are deploying the reaper to. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, create a stack set representing the account you wish to run the reaper in. Example invocation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation create-stack-set &lt;span class="nt"&gt;--stack-set-name&lt;/span&gt; reaper-aws-account &lt;span class="nt"&gt;--template-body&lt;/span&gt;
file://path/to/deploy_reaper.yaml &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_IAM &lt;span class="nt"&gt;--parameters&lt;/span&gt;
&lt;span class="nv"&gt;ParameterKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SLACKWEBHOOK,ParameterValue&lt;span class="o"&gt;=&lt;/span&gt;1234567 ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy the reaper into the account.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation create-stack-instances &lt;span class="nt"&gt;--stack-set-name&lt;/span&gt; reaper-aws-account &lt;span class="nt"&gt;--accounts&lt;/span&gt;
098765432109 &lt;span class="nt"&gt;--regions&lt;/span&gt; &lt;span class="s2"&gt;"us-west-1"&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt; &lt;span class="s2"&gt;"eu-west-1"&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Turning on the EC2 Reaper
&lt;/h2&gt;

&lt;p&gt;Once deployed, the EC2 Reaper will not reap anything unless the environment variable &lt;code&gt;LIVEMODE&lt;/code&gt; is set to &lt;code&gt;TRUE&lt;/code&gt;. It will only report what it would have done to Slack.&lt;/p&gt;

&lt;p&gt;When you want to activate the Reaper, update the parameter value &lt;code&gt;LIVEMODE&lt;/code&gt; to "TRUE"(the regex is case-insensitive).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws cloudformation update-stack-set &lt;span class="nt"&gt;--stack-set-name&lt;/span&gt; reaper-aws-account
&lt;span class="nt"&gt;--use-previous-template&lt;/span&gt; &lt;span class="nt"&gt;--parameters&lt;/span&gt; &lt;span class="nv"&gt;ParameterKey&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LIVEMODE,ParameterValue&lt;span class="o"&gt;=&lt;/span&gt;TRUE &lt;span class="nt"&gt;--capabilities&lt;/span&gt; CAPABILITY_IAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now you have learned how to control costs on AWS by reaping old EC2 instances. To learn more about our mission and product, sign up for our updates on &lt;a href="https://relay.sh"&gt;https://relay.sh&lt;/a&gt;. Our mission is to free you of tedious cloud-native workflows with event-driven automation! &lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Cut Unused EC2 instances with AWS Lambda</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Wed, 11 Mar 2020 21:20:20 +0000</pubDate>
      <link>https://forem.com/relay/how-to-cut-unused-ec2-instances-with-aws-lambda-1g28</link>
      <guid>https://forem.com/relay/how-to-cut-unused-ec2-instances-with-aws-lambda-1g28</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;How to Cut Unused EC2 Instances with AWS Lambda&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Uh… Why is this month’s AWS bill so high?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wlqn6DFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/634/0%2A2QaxxqswSJ71ZA42.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wlqn6DFx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/634/0%2A2QaxxqswSJ71ZA42.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Forgotten AWS EC2 instances have made everyone’s pockets hurt (including Puppet!). Take it from us (&lt;a href="http://relay.sh"&gt;relay.sh&lt;/a&gt; team) — if you don’t proactively clean up unused EC2 instances, cloud spending can quickly get out of control. However, it can be tedious to routinely check which EC2 instances are still in use, track down the old ones, and remove them. Luckily — we know how to automate these tasks!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Our mission is to free you to do what robots can’t.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post walks you through de-provisioning unused EC2 instances by using AWS Lambda and CloudFormation to deploy an EC2 reaper that uses simple Tags to cut down on spending.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/puppetlabs/aws_resource_reaper/tree/master/lambdas/ec2"&gt;To see the full code, check out this repo.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/puppetlabs/aws_resource_reaper/tree/master/lambdas/ec2"&gt;puppetlabs/aws_resource_reaper&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS EC2 Reaper overview
&lt;/h3&gt;

&lt;p&gt;The AWS Reaper works by checking and enforcing tags that are set on the EC2 instances. All EC2 instances must be tagged with a lifetime or a termination_date. The termination_date defines a future date after which the EC2 instance will be terminated. Alternatively, the Reaper looks for a lifetime tag– if found, it calculates a new future date and adds that date as the termination_date tag for the EC2 instance.&lt;/p&gt;

&lt;p&gt;First, let’s look at the &lt;a href="https://github.com/puppetlabs/aws_resource_reaper/blob/master/lambdas/ec2/reaper.py"&gt;reaper.py&lt;/a&gt;. The main reaper logic for handling instances is in the terminate_expired_instances function which lists instances and looks up the termination date tag for each instance:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  &lt;strong&gt;Improperly Tagged Instances&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If we find an instance that doesn’t have a termination_dateor we find the tag can’t be parsed, we stop it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This enables us to stop the b̶l̶e̶e̶d̶i̶n̶g̶ billing while we contact the instance owner to see if it should still be kept around.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Expired Instances&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;For all instances we find that are expired, we destroy:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Deploying the EC2 reaper&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now, we could just run this python script against different AWS regions and we’d already be better off than doing this manually. However, we would rather not spend time babysitting scripts at all. We’re going to deploy this into AWS using &lt;a href="http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-prereqs.html"&gt;CloudFormation Stacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Deploying the AWS reaper has two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploy_to_s3.yaml AWS CloudFormation template that places the lambda zip resources in S3 buckets in every region so that the deploy_reaper template can read them for Reaper deployment.&lt;/li&gt;
&lt;li&gt;deploy_reaper.yaml AWS CloudFormation template that installs the reaper creates the IAM role and deploys the lambda function to perform the instance reaping.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  deploy_to_s3 template
&lt;/h4&gt;

&lt;p&gt;In order to use this template, you must first manually create an S3 bucket that contains the resources to copy across all regions. You will need to do this once per region; S3 resources can be read between accounts but not between regions for AWS Lambda. This only needs to be done one time for the administrative account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually create an S3 bucket accessible from the administrative account. Zip up the two python reaper files, reaper.py and slack_notifier.py and place them in the bucket, naming them reaper.zip and slack_notifier.zip.&lt;/li&gt;
&lt;li&gt;From the administrative account, create a new stack set and use the deploy_to_s3 template. An example CLI invocation would look like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudformation create-stack-set --stack-set-name reaper-assets --template-body 
file://path/to/deploy\_to\_s3.yaml --capabilities CAPABILITY\_IAM --parameters
ParameterKey=OriginalS3Bucket,ParameterValue=reaperfiles
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy stack-set-instances for this stack set, one per region in the administrative account. Check the Amazon documentation for the most up-to-date region list. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudformation create-stack-instances --stack-set-name --accounts 123456789012
--regions "us-west-1" "us-west-2" "eu-west-1" ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  deploy_reaper template
&lt;/h4&gt;

&lt;p&gt;After the resources for the reaper have been distributed, you can use the deploy_reaper CloudFormation template to deploy the reaper into an account.&lt;/p&gt;

&lt;p&gt;You will need to follow the steps below for each account you are deploying the reaper into.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, create a stack set representing the account you wish to run the reaper in. Example invocation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudformation create-stack-set --stack-set-name reaper-aws-account --template-body
file://path/to/deploy\_reaper.yaml --capabilities CAPABILITY\_IAM --parameters
ParameterKey=SLACKWEBHOOK,ParameterValue=1234567 ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy the reaper into the account.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudformation create-stack-instances --stack-set-name reaper-aws-account --accounts
098765432109 --regions "us-west-1" "us-west-2" "eu-west-1" ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Turning on the EC2 Reaper
&lt;/h3&gt;

&lt;p&gt;Once deployed, the EC2 Reaper will not reap anything unless the environment variable LIVEMODE is set to TRUE. It will only report what it would have done to Slack.&lt;/p&gt;

&lt;p&gt;When the time comes to activate the Reaper, update the parameter value LIVEMODE to "TRUE"(the regex is case-insensitive).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws cloudformation update-stack-set --stack-set-name reaper-aws-account
--use-previous-template --parameters ParameterKey=LIVEMODE,ParameterValue=TRUE --capabilities CAPABILITY\_IAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Now you have learned how to control costs on AWS by reaping old EC2 instances. To learn more about our mission and product, sign up for our updates on &lt;a href="https://relay.sh/"&gt;relay.sh&lt;/a&gt;. Our mission is to free you of tedious cloud-native workflows with event-driven automation! For more content like this, please follow our medium page at &lt;a href="https://medium.com/relay-sh"&gt;https://medium.com/relay-sh&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>devops</category>
      <category>ec2</category>
      <category>cloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>Building the future of DevOps automation</title>
      <dc:creator>Kenaz Kwa</dc:creator>
      <pubDate>Wed, 04 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/relay/building-the-future-of-devops-automation-1foc</link>
      <guid>https://forem.com/relay/building-the-future-of-devops-automation-1foc</guid>
      <description>&lt;p&gt;&lt;a href="///static/f8102210984fbb59c4213ada4f887b5d/85053/1_N2sI7UnLjsVV-RrrC66PlA.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D13RpaFM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/f8102210984fbb59c4213ada4f887b5d/5a190/1_N2sI7UnLjsVV-RrrC66PlA.png" alt="Relay overview" title="Relay overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, we’re starting &lt;a href="//www.relay.sh"&gt;Relay by Puppet&lt;/a&gt;, a new initiative to build the future of cloud-based DevOps automation. This post captures our musings about the evolving world of cloud-native infrastructure and how Relay addresses this evolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Human-triggered operations
&lt;/h2&gt;

&lt;p&gt;Working with many of the largest companies in the world, we’ve seen server virtualization increase the number of things that operators have to manage from 1x to 10x. The automation we’ve built today enables us to scale to large infrastructure estates and eliminate this manual work. We’ve made one-click automation possible.&lt;/p&gt;

&lt;p&gt;However, in moving to public cloud, the number of things that operators have to manage has gone from 10x to 100x. A single VM running in a public cloud comprises a set of cloud resources that include the VM itself, the network and subnet it resides in, the IP address, the storage account, the disks, the security rules, the roles and permissions, and more. When you start to layer on container orchestration, the number of things to manage increases dramatically.&lt;/p&gt;

&lt;p&gt;Similarly, the number of tools that operators use every day and tie together to solve automation challenges has exploded in number and complexity. Operators must learn infrastructure provisioning with Terraform, configuration management with Bolt, Kubernetes deployments with Helm, building pipelines with Jenkins, maintain a whole flock of public cloud services — all in addition to responding to the endless queue of ServiceNow tickets, demanding that someone restart their server for them.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/9073015ac2c92170415e264976ef2ded/50966/19OrCdLrBcL4nlmKzZnI3FA.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mTOmy2wg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/9073015ac2c92170415e264976ef2ded/5a190/19OrCdLrBcL4nlmKzZnI3FA.png" alt="The now infamous Cloud Native Landscape" title="The now infamous Cloud Native Landscape"&gt;&lt;/a&gt;&lt;em&gt;the now infamous Cloud Native Landscape&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this world, human-triggered operations can no longer keep up. When you’re dealing with hundreds of tasks, even one-click automation is one click too many. Operators today need a different category of automation that responds to monitoring alerts, new service request tickets, cloud events and more. This kind of automation eliminates the low-value tasks operators spend their time doing today so that they can focus on the high-value work for their teams.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  When you’re dealing with hundreds of tasks, even one-click automation is one click too many.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Meet Relay
&lt;/h2&gt;

&lt;p&gt;Relay is an event-driven automation service for eliminating low-value DevOps tasks. Relay makes it easy to pull together the tools you use today into a single workflow and automate these workflows with an event-based trigger.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/fc539798eeda9adba790c130bf6b265c/37a83/1GQZjVLFgV-zYwAWBy3T_oQ.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DoLF2VNZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://github.com/static/fc539798eeda9adba790c130bf6b265c/5a190/1GQZjVLFgV-zYwAWBy3T_oQ.png" alt="Example DevOps events and workflows" title="Example DevOps events and workflows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We think there are a few useful scenarios here that either started out as problems for us or the DevOps engineers we talked to about Relay:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incident triggers:&lt;/strong&gt; Enabling PagerDuty or VictorOps incident to trigger creating a war room in Slack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ticket triggers:&lt;/strong&gt; Using a Jira ticket to trigger infrastructure provisioning of development environments with Terraform&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git triggers:&lt;/strong&gt; Deploying new versions of a containerized application to Kubernetes when a Github PR is merged&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring triggers:&lt;/strong&gt; Clearing out /var/log when SignalFx throws a disk utilization alert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud event triggers:&lt;/strong&gt; Making sure new S3 buckets are configured with the appropriate permissions when created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re not trying to boil the ocean here. Instead, we’re building a small set of use cases for DevOps teams that will make life way better for us (and hopefully you too).&lt;/p&gt;

&lt;h2&gt;
  
  
  Get involved
&lt;/h2&gt;

&lt;p&gt;We’re hard at work on our public beta launch (coming soon!) and we’d love to hear from you. What are the things that you’d like to automate today? &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSdwFjdpkX_DtAZveqY7uEPAsKhroutJXVSbfXRtVzYDmmpSRQ/viewform?usp=sf_link"&gt;Let us know&lt;/a&gt;. What’s a terrible idea (hello, storage policies should be separate from alerting)? &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSdwFjdpkX_DtAZveqY7uEPAsKhroutJXVSbfXRtVzYDmmpSRQ/viewform?usp=sf_link"&gt;Tell us&lt;/a&gt; in exchange for free swag!&lt;/p&gt;

&lt;p&gt;Over the next couple months, we’ll talk through our thinking, our bets, our progress, and what we’re hearing from folks like you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSdwFjdpkX_DtAZveqY7uEPAsKhroutJXVSbfXRtVzYDmmpSRQ/viewform?usp=sf_link"&gt;Let us know&lt;/a&gt; what to automate. We’ll give you free stuff!
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interested in following along? &lt;a href="https://dev.to/"&gt;Join our mailing list&lt;/a&gt; and we’ll certainly offer our earliest supporters perks along the way (Kickstarter-style vague promises — check!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PIYNGTYm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://github.com/ef6d40b627ee11eaa8dfe10df54e4ab8/1FVbiL-uIOGF2fd9Ib9aP3A.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PIYNGTYm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/http://github.com/ef6d40b627ee11eaa8dfe10df54e4ab8/1FVbiL-uIOGF2fd9Ib9aP3A.gif" alt="Thank you"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Good ideas (and products) don’t happen in a vacuum. And really, no ideas are new. We’re inspired by the work that teams at &lt;a href="https://zapier.com"&gt;Zapier&lt;/a&gt;, &lt;a href="http://stackstorm.com"&gt;Stackstorm&lt;/a&gt;, &lt;a href="https://github.com/features/actions"&gt;Github Actions&lt;/a&gt;, and others have created before us. In the next few months, we’ll talk about how we see Relay being similar or different from many of these tools.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
