Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automate root device volume's tagging using CloudFormation

I am not able to tag the root device volume attached to EC2 using CloudFormation's block device mapping because tags are not propagated to Amazon EBS volumes that are created from block device mappings. Can root device volume's tagging be automated using Cloudformation in any way? Thanks.

like image 998
Randhir Kumar Avatar asked Nov 10 '15 03:11

Randhir Kumar


People also ask

Does CloudFormation support Amazon EC2 tagging?

Q: Does AWS CloudFormation support Amazon EC2 tagging? Yes. Amazon EC2 resources that support the tagging feature can also be tagged in an AWS template.

How do I add tags to multiple EC2 instances?

To add tags to—or edit or delete tags of—multiple resources at once, use Tag Editor. With Tag Editor, you search for the resources that you want to tag, and then manage tags for the resources in your search results. Sign in to the AWS Management Console. On the navigation bar, choose Services.

Can we create EC2 key pair using CloudFormation?

The use of some AWS CloudFormation resources and templates will require you to specify an Amazon EC2 key pair for authentication, such as when you are configuring SSH access to your instances. Amazon EC2 key pairs can be created with the AWS Management Console.


1 Answers

CloudFormation

This has just shipped in CloudFormation settable via the property

PropagateTagsToVolumeOnCreation

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-propagatetagstovolumeoncreation

User Data

This is possible to do using UserData - if you are running a linux host with cloudinit and the awscli installed, it's possible to run the following in your UserData script to tag all the volumes associate with an Instance

"VOLUME_IDS=$(aws ec2 describe-volumes --output text --filters Name=attachment.instance-id,Values=$(curl http://169.254.169.254/latest/meta-data/instance-id) --query 'Volumes[].VolumeId')",
"aws ec2 create-tags --resources ${VOLUME_IDS} --tags Key=my,Value=tag"
  • retrieves current instance id
  • uses the instance id as filter in describe volumes
  • jmespath query to returns just the volume ids
  • volume ids passed to create tags with the tag/s you wish to add

ensure that when you launch your EC2 Instance it has an Instance IAM Policy that enables it to create tags and describe volumes

"PolicyDocument": {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ec2:CreateTags",
                "ec2:DescribeVolumes"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

## CloudWatch Events Another way to automate this is via CloudWatch Events, set up an Events rule listening for and EC2 State Change, then tag The volumes in a Lambda function, I've included a couple of CloudFormation snippets below

LambdaEC2CopyTagsToEBS:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
    Policies:
      - PolicyName: LambdaEC2CopyTagsToEBS
        PolicyDocument:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action:
                - ec2:DescribeInstances
                - ec2:CreateTags
              Resource: '*'

            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: '*'

LambdaEC2CopyTagsToEBSEvent:
  Type: AWS::Events::Rule
  Properties:
    Description: Invokes CopyInstanceTagsToEBSVolumes when an Instance starts running
    EventPattern:
      source:
        - aws.ec2
      detail-type:
        - EC2 Instance State-change Notification
      detail:
        state:
          - running
    State: ENABLED
    Targets:
      - Arn: !GetAtt CopyInstanceTagsToEBSVolumes.Arn
        Id: !Ref CopyInstanceTagsToEBSVolumes

CopyInstanceTagsToEBSVolumes:
  Type: AWS::Lambda::Function
  Properties:
    Description: Copies Tags from and EC2 to all its EBS Volumes
    Code:
      ZipFile: |
        import boto3
        ec2 = boto3.client('ec2')


        def get_volume_ids(instance):
            for device in instance.get('BlockDeviceMappings', []):
                yield device.get('Ebs', {}).get('VolumeId')


        def handler(event, context):
            state, instance_id = event['detail']['state'], event['detail']['instance-id']
            if state == 'running':
                instance = ec2.describe_instances(InstanceIds=[instance_id])
                instance = instance['Reservations'][0]['Instances'][0]
                volume_ids = get_volume_ids(instance)
                tags = [tag for tag in instance['Tags'] if not tag['Key'].startswith('aws:')]
                ec2.create_tags(Resources=list(volume_ids),
                                Tags=tags
                                )

    Handler: index.handler
    Role: !GetAtt LambdaEC2CopyTagsToEBS.Arn
    Runtime: python3.6
    Timeout: 5


EventsInvokeCopyInstanceTagsToEBSVolumes:
  Type: AWS::Lambda::Permission
  Properties:
    Action: lambda:InvokeFunction
    FunctionName: !Ref CopyInstanceTagsToEBSVolumes
    Principal: events.amazonaws.com
    SourceArn: !GetAtt LambdaEC2CopyTagsToEBSEvent.Arn
like image 170
georgealton Avatar answered Sep 22 '22 20:09

georgealton