Are dead projects and under-utilized servers lingering in your AWS environment? These resources are costing you money and leave open vulnerabilities or attack vectors that can create nightmare scenarios for your company. Cleaning them up saves not only time and money, it also closes the window on ransomware attacks and data exfiltration. "Argh!!" that is a monster project. Fortunately, public cloud has evolved an answer…

Project Minimalist: Leave the tag on and keep the receipt! | Alice ...

Tag it.

Tags are simply a key-value pair. In other words, a custom attribute you can create. Amazon Web Services allows you to create up to 50 custom user tags for each resource in your AWS environment.

What does a tag look like? A tag has two parts:

  • a Key: the name of the attribute you reference.
  • a Value: the value of that attribute for that resource.

For example:

Above is an example of a unique custom tag that creates a friendly name for your resource - in this case, probably an EC2 instance.  But tags can be useful attributes that help you identify groups of resources. For example:

Once created, these tags can then be used to apply policies or actions to every resource that matches that key-value pair(s). For example, upon completion of the marketing team's "rebrand" project we can create an action to STOP all resources tagged for the project as above by using a condition that matches the tags we defined for those resources.

Hold on - we will get to an example of how to do that soon.

Before we do so, let's look at why tagging is critical and why everyone should be doing it.

Table of Contents:

1. Why tagging is important.

2. Tagging best practices.

3. Example light weight tagging strategy.

4. Automate using tags to schedule resources.

Part 1: Why tagging?

"Gosh Nick, this seems like a lot of extra work."

Me:

Will Ferrell Brennan GIF - Find & Share on GIPHY

This is one-time work initially and can be automated for new resources. (Automatic AWS EC2 tagging example). But believe me, I feel your pain.

The benefits may not be entirely obvious at first glance. There are several core use cases.

AWS Cost Allocation: both AWS Cost Explorer and Cost and Usage Report support tags for breaking down AWS costs to better understand your AWS bill.

AWS automation activities: AWS pricing is based heavily on utilization. Tags can be used to opt in or opt out of automated tasks such as start/stop scripts for turning off non-essential resources during off hours. (This can save as much a 70% off your AWS costs alone.)

We are going to do ^^ this ^^ for EC2 instances below.

Backup and system patching: Use tags to support these processes and ensure resources are not left out of the patch cycle, creating a security nightmare.

AWS Identity and Access Management: AWS IAM polices support the use of tags to limit user and role permissions based on specific tags and their values.

Security and Compliance: use tags to identify resources requiring specific compliance-based activities and then created automated checks to ensure that the controls are in place and working.

The Well Managed Cloud: tags are also at the core of additional tools such as Cloud Custodian or Tenacity Cloud's CTRL platform that create a much more robust and customizable framework for driving automated compliance, security, cost optimization, and governance at scale.

Part 2: Tagging Best Practice

First: DON'T TAG IN A VACUUM!

Employ a cross functional team, preferably your Cloud Center of Excellence (CCoE).

If you haven't formed a CCoE, that's a big topic explained here.

No CCoE? No worries. Consider assembling a small team consisting of representatives who will most benefit from strong cloud and tagging governance. Some examples:

  • IT finance
  • your security group
  • application owners
  • your automation team
  • middleware and database teams
  • your cloud ops teams
  • IT compliance

Naming

Tags are cAsE sEnSiTiVe. This applies to both Keys and Values.

Pick a naming standard (the devs know what I mean). Don't overthink it, just go with one that is natural for you and the team that will be using tags. Here are some examples:

  • Camel Case: costCenter
  • Pascal Case: CostCenter
  • Snake Case: cost_center
  • Kebab Case: cost-center

Or bring your own, the point is to be consistent.

Restrictions

Keep these in mind as you create your tagging strategy:

  • Maximum key length – 128 Unicode characters in UTF-8
  • Maximum value length – 256 Unicode characters in UTF-8
  • Although EC2 allows for any character in its tags, other services are more restrictive. The allowed characters across services are: letters, numbers, and spaces representable in UTF-8, and the following characters: + - = . _ : / @.
  • Tag keys and values are case-sensitive.
  • The aws: prefix is reserved for AWS use. If a tag has a tag key with this prefix, then you can't edit or delete the tag's key or value. Tags with the aws: prefix do not count against your tags per resource limit.

Avoid Multi-value Tags

For AWS cost management and charge-backs, consider using a combination of Linked Accounts and Cost Allocation tags. This can simplify overly complex cost allocation tags and avoid trying to create multi-value tags that require post-processing support.  Example of what NOT to do:

Trust me. This becomes a mess to manage. You don't like messes. Neither do I. Don't do it.

Less is More

Start only with what you need. Don't design an aircraft carrier when what you need right now is a row boat. Start rowing sooner.

Tag Everything

AWS console can be overwhelming even for administrators. It can be frustrating to actually locate and see all of your AWS resources in one place or understand the full scope of your environment. Tagging makes this much easier.

Once tagging is implemented, you can use Resource Groups to create and view groups of resources based on the tags you have created.

Leveraging a tool like Tenacity's Cloud CTRL platform will further eliminate the frustration and can make the initial tagging activity and ongoing tagging compliance audits easy.

Use Automation to Proactively Tag Resources

Do this early. (Automatic AWS EC2 tagging example)

That should get your started on AWS Tagging Best Practices. For an in depth look, go here.

Part 3: Example AWS Tagging Implementation

For our example we will imagine a software company that offers both a SaaS product and a retail product suite with downloadable modules. Their first tagging strategy might look like this:

They will also leverage a Key: "name" tag to create a friendly name for each of the resources in their environment.

With the tagging strategy outlined, they will log into the AWS console and begin deploying the first tags.

Then it's time to set up their monthly cost allocation report through AWS Billing and Cost Management.

Part 4: Automate using tags to schedule resources AND reduce AWS costs

Now that our AWS tagging strategy is implemented, it's finally time for some automation. Here is an easy example to tackle right away.

AWS Resource Scheduling

There are several ways to tackle this problem. For our purposes we are going to use an AWS Lambda function triggered by an AWS CloudWatch event.  Let's set up our test environment first:

Launch AWS console and log in. Navigate to  EC2 and Launch 4 new free tier instances. Navigate to EC2 -> Instances and add some sample tags as outlined in the table above.

Give two of your test instances the schedule:office-hours tag

Now the test environment is ready.

IAM Policy

First we create an IAM policy using the JSON policy editor.

Paste this JSON policy into the policy editor:

  1. In the AWS Console, click Services and search for IAM.
  2. You are now in the Identity and Access Management (AIM) dashboard. Under Access Management navigate to Policies.
  3. Click Create Policy.
  4. Click the JSON tab.

Paste this JSON policy into the policy editor:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:Start*",
                "ec2:Stop*",
                "ec2:DescribeInstances"
            ],
            "Resource": "*"
        }
    ]
}

  1. Click Review Policy. Give your new policy a Name. Click Create Policy.
  2. Under Access Management navigate to Roles.
  3. Click Create Role.
  4. Select AWS Service and then click on Lambda.
  5. Click Next: Permissions.
  6. Search for the IAM policy you just created above. Click Next: Tags. Click Next: Review.
  7. Give your Role a name and click Create role.

Lambda Function

Now it's time to create a Lambda function to stop and start our instances. In this example we will limit ourselves to a specific region.

  1. In the Lambda console, choose Create function.
  2. Choose Author from scratch.
  3. Under Basic information add the following:
    • In Function name enter a name for your function. For example, "StopEC2Instances-office-hours".
    • Click Runtime, choose Python 3.7.
    • Under Permissions, expand Choose or create an execution role.
    • Under Execution role, Choose Use an existing role.
    • Under Existing role, type the IAM role you created above.
  4. Click Create function.
  5. Copy this code, and then under Function code, paste it into the editor pane in the code editor (lambda_function). This code stops the EC2 instances associated with the schedule:office-hours tag.

Note: For region, replace "us-east-1" with the AWS Region that your instances are in.

import boto3
region = 'us-east-1'
instances = []
tagkey = 'schedule'
tagvalue = 'office-hours'
ec2 = boto3.client('ec2', region_name=region)

ec2client = boto3.client('ec2')
 
response = ec2client.describe_instances(
    Filters=[
        {
            'Name': 'tag:'+tagkey,
            'Values': [tagvalue]
        }
    ]
)

for reservation in (response["Reservations"]):
    for instance in reservation["Instances"]:
        instances.append(instance["InstanceId"])


def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))
  1. Under Basic settings set the Timeout to 10 seconds.
  2. Click Save.

Repeat the above steps for a new Lambda function to start your instances. Choose a name such as "StartEC2Instances-office-hours".

Use the following code in the code_editor (lambda_function)

import boto3
region = 'us-east-1'
instances = []
tagkey = 'schedule'
tagvalue = 'office-hours'
ec2 = boto3.client('ec2', region_name=region)

ec2client = boto3.client('ec2')
 
response = ec2client.describe_instances(
    Filters=[
        {
            'Name': 'tag:'+tagkey,
            'Values': [tagvalue]
        }
    ]
)

for reservation in (response["Reservations"]):
    for instance in reservation["Instances"]:
        instances.append(instance["InstanceId"])


def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

Test Your Lambda Functions

  1. In the Lambda console, choose Functions.
  2. Select one of the functions you created.
  3. Click Actions, then choose Test.
  4. Choose Create new test event.
  5. Give it an Event name and click Create (ignore the JSON code for the test event, it will not use it)
  6. Click Test to execute the function.
  7. Check the EC2 console to see your instances stop/start
  8. Repeat for the other function you created.

Create an AWS CloudWatch Event

Now it's time to put it all together and trigger the lambda function with an Event.

  1. Open the AWS CloudWatch console.
  2. Under Events, choose Rules.
  3. Click Create rule.
  4. Under Event Source, choose Schedule.
  5. Choose Cron expression and paste in the following cron expression for starting your instances every day of the work week (Monday through Friday) at 8:00 AM EDT.
0 12 ? * MON-FRI *

(Here is more information on customizing your cron expression.)

  1. Under Targets, click Add target.
  2. Select Lambda function.
  3. For Function, choose the function you created to start your EC2 instances.
  4. Click Configure details.
  5. Add a Name and Description.
  6. Make sure State is Enabled.
  7. Click Create rule.

Repeat the above for your Stop event, using the following cron expression to stop your instances every day of the work week (Monday through Friday) at 6 PM EDT.

0 22 ? * MON-FRI *

Be sure to select the Lambda Function for stopping your instances.

You are now all set.  You can adjust your rules or create new test rules with different cron expressions to test your events immediately.

Wrap Up

There are several other options for implementing scheduled instances, with additional capability and increasing complexity, including the AWS Instance Scheduler solution, event driven API calls, and Cloud Custodian. We will cover off on those in a future post.

More importantly, there is near limitless potential to automate within your AWS environment to both save you money and remove the headache of maintenance; the lack of which leads to inevitable waste, cost, downtime, confusion, and worst of all, vulnerability.

There are solutions to making complex policy sets insanely easy, check out Tenacity Cloud's CTRL platform and join our beta program.

And you can always follow us on LinkedIn | Twitter | Facebook or sign up for our mailing list for more automation, cost saving, security and compliance examples.

Share this post on LinkedIn