Zack
Zack

Reputation: 1

How do you automate tagging using a Lambda function on AWS?

I'm trying to automate tagging for the following resources on AWS:

Currently I have a Lambda function that is almost identical to this article: How to Automatically Tag Amazon EC2 Resources in Response to API Events | AWS Security Blog

How can I modify this Lambda function so it tags the above resources as well?

I've tried finding documentation on how to tag these specific resources and I can't seem to find anything that's relevant to tagging using a Lambda function.

elif eventname == 'CreateImage':
    ids.append(detail['responseElements']['imageId'])
    logger.info(ids)

elif eventname == 'CreateSnapshot':
    ids.append(detail['responseElements']['snapshotId'])
    logger.info(ids)
elif eventname == 'CreateSecurityGroup':
    ids.append(detail['responseElements']['groupId'])
else:
    logger.warning('Not supported action')

The above code is adding tags for EC2, but we need it to add tags to the resources I listed above.

Upvotes: 0

Views: 11498

Answers (3)

Rahul
Rahul

Reputation: 111

To tag resources upon creation you need to use Lambda, Cloudwatch events and some automation.

You can tag resources with the IAM ARN of the resource creator and resource created-date with the documentation available here, this is an open-source tagging solution for AWS. This will help you tag your resources with the IAM ARN of the creator and the resource created-date.

There are two ways you can implement the solution available on the above link, 1. Shell Script and 2. CloudFormation template.

Upvotes: 0

ojhurst
ojhurst

Reputation: 412

This should help on a few of them.

Here are the cloudwatch event patterns:

{
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "ec2.amazonaws.com",
      "rds.amazonaws.com",
      "lambda.amazonaws.com",
      "s3.amazonaws.com",
      "dynamodb.amazonaws.com",
      "elasticfilesystem.amazonaws.com"
    ],
    "eventName": [
      "CreateVolume",
      "RunInstances",
      "CreateImage",
      "CreateSnapshot",
      "CreateDBInstance",
      "CreateFunction20150331",
      "UpdateFunctionConfiguration20150331v2",
      "UpdateFunctionCode20150331v2",
      "CreateBucket",
      "CreateTable",
      "CreateMountTarget"
    ]
  }
}

and then here is the corresponding lambda code which will need a few modifications for your environment.

from __future__ import print_function
import json
import boto3
import logging
import time
import datetime

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    logger.info('################  Event: ############## ' + str(event))
    #print('Received event: ' + json.dumps(event, indent=2))

    ids = []

    try:
        region = event['region']
        detail = event['detail']
        eventname = detail['eventName']
        arn = detail['userIdentity']['arn']
        principal = detail['userIdentity']['principalId']
        userType = detail['userIdentity']['type']

        if userType == 'IAMUser':
            user = detail['userIdentity']['userName']

        else:
            user = principal.split(':')[1]


        logger.info('principalId: ' + str(principal))
        logger.info('region: ' + str(region))
        logger.info('eventName: ' + str(eventname))
        logger.info('detail: ' + str(detail))

        ec2_client = boto3.resource('ec2')
        lambda_client = boto3.client('lambda')
        rds_client = boto3.client('rds')
        s3_client = boto3.resource('s3')
        ddb_client = boto3.client('dynamodb')
        efs_client = boto3.client('efs')

        if eventname == 'CreateVolume':
            ids.append(detail['responseElements']['volumeId'])
            logger.info(ids)

        elif eventname == 'RunInstances':
            items = detail['responseElements']['instancesSet']['items']
            for item in items:
                ids.append(item['instanceId'])
            logger.info(ids)
            logger.info('number of instances: ' + str(len(ids)))

            base = ec2_client.instances.filter(InstanceIds=ids)

            #loop through the instances
            for instance in base:
                for vol in instance.volumes.all():
                    ids.append(vol.id)
                for eni in instance.network_interfaces:
                    ids.append(eni.id)

        elif eventname == 'CreateImage':
            ids.append(detail['responseElements']['imageId'])
            logger.info(ids)

        elif eventname == 'CreateSnapshot':
            ids.append(detail['responseElements']['snapshotId'])
            logger.info(ids)

        elif eventname == 'CreateFunction20150331':
            try:
                functionArn = detail['responseElements']['functionArn']
                lambda_client.tag_resource(Resource=functionArn,Tags={'CreatedBy': user})
                lambda_client.tag_resource(Resource=functionArn,Tags={'DateCreated': time.strftime("%B %d %Y")})
            except Exception as e:
                logger.error('Exception thrown at CreateFunction20150331' + str(e))
                pass
        elif eventname == 'UpdateFunctionConfiguration20150331v2':
            try:
                functionArn = detail['responseElements']['functionArn']
                lambda_client.tag_resource(Resource=functionArn,Tags={'LastConfigModifiedByNetID': user})
            except Exception as e:
                logger.error('Exception thrown at UpdateFunctionConfiguration20150331v2' + str(e))
                pass
        elif eventname == 'UpdateFunctionCode20150331v2':
            try:
                functionArn = detail['responseElements']['functionArn']
                lambda_client.tag_resource(Resource=functionArn,Tags={'LastCodeModifiedByNetID': user})
            except Exception as e:
                logger.error('Exception thrown at UpdateFunctionCode20150331v2' + str(e))
                pass
        elif eventname == 'CreateDBInstance':
            try:
                dbResourceArn = detail['responseElements']['dBInstanceArn']
                rds_client.add_tags_to_resource(ResourceName=dbResourceArn,Tags=[{'Key':'CreatedBy','Value': user}])
            except Exception as e:
                logger.error('Exception thrown at CreateDBInstance' + str(e))
                pass
        elif eventname == 'CreateBucket':
            try:
                bucket_name = detail['requestParameters']['bucketName']
                s3_client.BucketTagging(bucket_name).put(Tagging={'TagSet': [{'Key':'CreatedBy','Value': user}]})
            except Exception as e:
                logger.error('Exception thrown at CreateBucket' + str(e))
                pass
        elif eventname == 'CreateTable':
            try:
                tableArn = detail['responseElements']['tableDescription']['tableArn']
                ddb_client.tag_resource(ResourceArn=tableArn,Tags=[{'Key':'CreatedBy','Value': user}])
            except Exception as e:
                logger.error('Exception thrown at CreateTable' + str(e))
                pass
        elif eventname == 'CreateMountTarget':
            try:
                system_id = detail['requestParameters']['fileSystemId']
                efs_client.create_tags(FileSystemId=system_id, Tags=[{'Key':'CreatedBy','Value': user}])
            except Exception as e:
                logger.error('Exception thrown at CreateMountTarget' + str(e))
                pass
        # todo: EMR and Glacier also possible candidates
        else:
            logger.warning('No matching eventname found in the Auto Tag lambda function (Ln 118)')

        if ids:
            for resourceid in ids:
                print('Tagging resource ' + resourceid)
            ec2_client.create_tags(Resources=ids, Tags=[{'Key': 'CreatedBy', 'Value': user}])

        logger.info(' Remaining time (ms): ' + str(context.get_remaining_time_in_millis()) + '\n')
        return True
    except Exception as e:
        logger.error('Something went wrong: ' + str(e))
        return False

You are kind of limited by what is supported by Cloudwatch events, but this will hopefully help you knock out a few of the ones on your list.

Upvotes: 3

Vladyslav Didenko
Vladyslav Didenko

Reputation: 1631

Maybe something from python boto lib would help (on example of RDS) :

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.add_tags_to_resource

response = client.add_tags_to_resource(
ResourceName='arn:aws:rXXXXX,
Tags=[
{
'Key': 'Staging',
'Value': '2019',
},
], )

Upvotes: 0

Related Questions