CloudFormationでEC2インスタンスのルートボリュームにタグ付けする
AWSを愛する皆さま、こんにちは。コンサルティング部の西野(@xiyegen)です。
CloudFormationでEC2インスタンスを作成する際はAWS::EC2::Instanceというリソースを指定します。
このAWS::EC2::Instance
にはルートボリュームのタグ付けを担うプロパティが存在しません。
それでもなんとかしてインスタンス作成時にこのタグ付けを実施できないか調べていたところ、公式のナレッジを発見しました。
AWS CloudFormation が作成したインスタンスからルートボリュームにタグを付ける方法を教えてください。
当該ページで紹介されているテンプレートが大きめだったので、あっさり味に加工した自作テンプレートとともに仕組みを紹介したいと思います。
目次
3行まとめ
テンプレート内で行われている処理は単純です。
- UserDataによりインスタンスメタデータからリージョン情報およびインスタンスIDを取得する。
- UserDataからAWS CLIを使用しタグ付け対象ボリュームのID取得&タグ付けを実行する(
aws ec2 describe-instances
&aws ec2 create-tags
)。 - 上記のコマンドを実行するために
ec2:Describe*
とec2:CreateTags
の権限をインスタンスへ付与する。
注意
AWSのリソースタグは、IAMによるアクセス制御やAmazon DLMによるスナップショットターゲットの指定など、様々な用途に用いられます。
リソースタグのユースケースによってはec2:CreateTags
権限の付与が意図せぬ結果をまねくことがあります。あらかじめご留意ください。
テンプレート
前提条件
- AWS CLIが必要なのでAmazon Linux 2の最新版AMI(2020/02/26時点)を使用しています。
- 説明の簡便化のためテンプレートから
Parameters
セクションを省いてあります。 - ルートボリュームにNameタグ
MySweetRootVolume
を設定するテンプレートです。 *1
本体
AWSTemplateFormatVersion: 2010-09-09 Resources: LinuxInstance: Type: 'AWS::EC2::Instance' Properties: ImageId: ami-0af1df87db7b650f4 InstanceType: t2.micro AvailabilityZone: ap-northeast-1a SubnetId: subnet-XXXXXXXXXXXXXXXXX IamInstanceProfile: !Ref InstanceProfile KeyName: wo-de-yaoshi UserData: Fn::Base64: | #!/bin/sh AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone) AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`" AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id) ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId) aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=Name,Value=MySweetRootVolume Tags: - Key: Name Value: MySweetInstance BlockDeviceMappings: - DeviceName: "/dev/xvda" Ebs: VolumeSize: 8 VolumeType: "gp2" InstanceRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: taginstancepolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'ec2:Describe*' - 'ec2:CreateTags' Resource: '*' InstanceProfile: Type: 'AWS::IAM::InstanceProfile' Properties: Path: / Roles: - !Ref InstanceRole
解説
UserData
UserData: Fn::Base64: | #!/bin/sh AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone) AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`" AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id) ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId) aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=Name,Value=MySweetRootVolume
ルートボリュームへのタグ付けの肝となるのは本テンプレートのUserData部分です。
- 必要となるパラメータ(
$AWS_REGION
と$AWS_INSTANCE_ID
)をインスタンスメタデータから取得 aws ec2 describe-instances
でルートボリュームのIDを取得aws ec2 create-tags
でタグ付けを実行(Key=Name,Value=MySweetRootVolume)
という流れで処理を行っています。
IAMロールとインスタンスプロファイル
InstanceRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: taginstancepolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'ec2:Describe*' - 'ec2:CreateTags' Resource: '*' InstanceProfile: Type: 'AWS::IAM::InstanceProfile' Properties: Path: / Roles: - !Ref InstanceRole
ボリュームのID取得とタグ付けに必要なec2:Describe*
とec2:CreateTags
の権限を持つポリシーを作成し、作成対象のインスタンスに付与しています。
やってみた
先述したテンプレートでスタックを作成します。
EC2インスタンスができています。 ルートボリュームを見てみると……。
しっかりNameタグを付与できています。
終わりに
このブログがほんの少しでも世界を良くできれば嬉しいです。 コンサルティング部の西野(@xiyegen)がお送りしました。
脚注
- aws ec2 create-tagsコマンドの--tagsオプションでKeyおよびValueを指定することにより任意のタグを付与できます。 ↩