Randhir
Randhir

Reputation: 812

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.

Upvotes: 10

Views: 2332

Answers (1)

georgealton
georgealton

Reputation: 1039

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"

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

Upvotes: 9

Related Questions