Skip to content

Instantly share code, notes, and snippets.

@DanyC97
Forked from tomekklas/CopyTags.yml
Created November 2, 2020 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanyC97/530b47e35a7e4e85a17eb247142c041a to your computer and use it in GitHub Desktop.
Save DanyC97/530b47e35a7e4e85a17eb247142c041a to your computer and use it in GitHub Desktop.
Copy tags from EC2 to associated resources
---
AWSTemplateFormatVersion: 2010-09-09
Description: Copy tags from EC2 to associated resources
Resources:
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Sid: ""
Path: "/"
Policies:
- PolicyName: "AllowXRay"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- xray:PutTraceSegments
- xray:PutTelemetryRecords
Resource:
- "*"
- PolicyName: "Create-EC2"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- ec2:CreateTags
Resource:
- !Sub "arn:aws:ec2:${AWS::Region}::snapshot/*"
- !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:volume/*"
- !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*"
- PolicyName: "CreateLogs"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- logs:CreateLogStream
Resource:
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*"
- PolicyName: "DescribeGeneric"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- elasticloadbalancing:DescribeLoadBalancers
- ec2:DescribeInstances
- ec2:DescribeNetworkInterfaces
- elasticloadbalancing:DescribeTags
- ec2:DescribeTags
- ec2:DescribeVolumes
Resource:
- "*"
Lambda:
Type: AWS::Lambda::Function
DependsOn:
- Role
Properties:
Handler: "index.lambda_handler"
Role: !GetAtt Role.Arn
Runtime: python3.7
MemorySize: 128
Timeout: 300
TracingConfig:
Mode: Active
Code:
ZipFile: !Sub |
import boto3
COPYABLE = ["ApplicationName", "EnvironmentType", "ProvisionedBy", "RequestedBy"]
def lambda_handler(event, context):
ec2();
elb();
elbv2();
return;
def ec2():
print('Processing EC2 Instances')
instances = boto3.resource('ec2', region_name='${AWS::Region}').instances.all()
for instance in instances:
tags = [t for t in instance.tags or [] if t['Key'] in COPYABLE]
if not tags:
continue
# Tag the EBS Volumes
for vol in instance.volumes.all():
print('Updating tags for {}'.format(vol.id))
vol.create_tags(Tags=tags)
# Tag the Elastic Network Interfaces
for eni in instance.network_interfaces:
print('Updating tags for {}'.format(eni.id))
eni.create_tags
def elb():
print('Processing ELB Instances')
def filter(i):
return (i.get('RequesterId') == 'amazon-elb' and
i['Description'].startswith('ELB') and
'/' not in i['Description'])
tags = _get_elb_tags('elb')
for interface in _network_interfaces(filter):
name = interface['Description'].split(' ')[1]
if name not in tags:
continue
_tag_network_interface(interface['NetworkInterfaceId'], tags[name])
def elbv2():
print('Processing ELBv2 Instances')
def filter(i):
return (i.get('RequesterId') == 'amazon-elb' and
i['Description'].startswith('ELB') and
'/' in i['Description'])
tags = _get_elb_tags('elbv2')
for interface in _network_interfaces(filter):
name = interface['Description'].split('/')[1]
if name not in tags:
continue
_tag_network_interface(interface['NetworkInterfaceId'], tags[name])
def _get_elb_tags(name='elb'):
if name == 'elb':
page_name = 'LoadBalancerDescriptions'
key = 'LoadBalancerName'
kwname = 'LoadBalancerNames'
elif name == 'elbv2':
page_name = 'LoadBalancers'
key = 'LoadBalancerArn'
kwname = 'ResourceArns'
else:
raise ValueError('Invalid name: {}'.format(name))
tags = {}
client = boto3.client(name, region_name='${AWS::Region}')
paginator = client.get_paginator('describe_load_balancers')
for page in paginator.paginate():
for lb in page[page_name]:
response = client.describe_tags(**{kwname: [lb[key]]})
lb_tags = [item for sublist in
[r.get('Tags', []) for r in response['TagDescriptions']]
for item in sublist]
tags[lb['LoadBalancerName']] = [t for t in lb_tags if
t['Key'] in COPYABLE]
tags[lb['LoadBalancerName']].append(
{'Key': 'Name', 'Value': lb['LoadBalancerName']})
return tags
def _network_interfaces(filter=None):
client = boto3.client('ec2', region_name='${AWS::Region}')
paginator = client.get_paginator('describe_network_interfaces')
for page in paginator.paginate():
for interface in page['NetworkInterfaces']:
if filter and not filter(interface):
continue
yield interface
def _tag_network_interface(eni_id, tags):
print('Updating tags for {}'.format(eni_id))
ec2 = boto3.resource('ec2', region_name='${AWS::Region}')
eni = ec2.NetworkInterface(eni_id)
eni.create_tags(Tags=tags)
LambdaScheduledRule:
Type: AWS::Events::Rule
Properties:
Description: LambdaCopyTagsScxheduledRule
ScheduleExpression: "rate(1 day)"
State: ENABLED
Targets:
-
Arn:
Fn::GetAtt:
- "Lambda"
- "Arn"
Id: "ScheduleLambda"
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref Lambda
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !GetAtt LambdaScheduledRule.Arn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment