EC2 workloadsを自動でタグ付けし、AWSコストを正確に按分する方法をご紹介します。
「名無し」インスタンス問題
AWS EC2の利用状況を確認していると、名前が付いていない、あるいは付いていても用途がわからないインスタンスやボリュームに出くわすことがあります。完全な無駄遣いの可能性もあれば、本番workloadsを支える重要なリソースである可能性もあります。

us-east-1で月額388ドルを消費している「DO NOT DELETE」m3.2xlargeインスタンス
こうしたインスタンスは数年前から動き続けていることもあり、組織内に詳細を知る人がおらず、接続用の認証情報も残っていないというケースが少なくありません。
この問題を防ぐため、多くの企業ではタグ付けポリシーを定め、プロビジョニングするすべてのインスタンスにName/Owner/Projectなどのタグを必須としています。
EC2インスタンスとボリュームへのタグ付けに追加料金はかかりません…
…とはいえ、人がインスタンスを起動したり、自動化スクリプトで起動したりする以上、運用上のミスはどうしても発生します。
そこで、AWS向けに自動タグ付けのソリューションを書きました(Google Cloud版はこちら)。インスタンスにはOwnerタグが、ボリュームにはOwnerとAttachedInstanceタグが自動で付与されます。
これにより、用途不明のインスタンスやボリュームに遭遇しても、タグから誰がセットアップしたのかをすぐに特定できるようになります。
**自動タグ付けの仕組み**

- ユーザーがAWS EC2インスタンスを作成
- AWS CloudTrailがAPIコールを記録し、AWS EventBridgeを呼び出す
- AWS EventBridgeがLambda関数を起動
- AWS Lambdaがインスタンスとそのボリュームにタグを付与
インスタンスの起動情報を受け取ったAWS Lambda関数は、インスタンスにOwnerタグを付与します。タグの値には次のいずれかが入ります。
- IAMユーザー
- Assume Role(例:AutoScaling Role、SSOユーザーなど)
- ルートユーザー

インスタンス画面。下部にタグが表示されます
続いてLambdaは、そのインスタンスに紐づくすべてのボリュームに「Owner」タグと「AttachedInstance」タグを付与します。「Owner」タグの値はインスタンスの「Owner」タグと同じで、「AttachedInstance」タグにはinstance-idと、設定されていればインスタンス名が入ります。

ボリューム画面。下部にタグが表示されます
実装手順
- CloudTrailのページを開き、「Create trail」をクリックします。

2. trailに名前を付けます。

3. 下にスクロールしてCloudTrail用S3バケットの名前を設定し、Createをクリックします。

4. Lambdaのダッシュボードに移動し、「Create function」をクリックします。

5. 関数名を入力し、Runtimeのドロップダウンから「Python 3.8」を選択して「Create Function」をクリックします。

6. GitHubリポジトリのコードを貼り付け、「Save」をクリックします。

7. 「Basic settings」までスクロールし、Editボタンをクリックします。
Lambda関数のタイムアウトを1分に変更します。
続いてSaveボタンをクリックします。

8. ページ上部に戻り、Permissionsをクリックして、Role名をクリックします。

9. 「Add inline policy」ボタンをクリックします。

10. JSONボタンをクリックし、以下のIAMポリシーを貼り付けてReview policyをクリックします。
{
"Version": "2012-10-17",
"Statement": [\
{\
"Sid": "VisualEditor0",\
"Effect": "Allow",\
"Action": "ec2:CreateTags",\
"Resource": [\
"arn:aws:ec2:*:*:instance/*",\
"arn:aws:ec2:*:*:volume/*"\
]\
},\
{\
"Sid": "VisualEditor1",\
"Effect": "Allow",\
"Action": [\
"ec2:DescribeInstances",\
"ec2:DescribeVolumes"\
],\
"Resource": "*"\
}\
]
}
このポリシーにより、Lambda関数はインスタンスのボリュームを取得し、インスタンスおよびボリュームにタグを付与できるようになります。
11. ポリシーに名前を付け、Create policyをクリックします。

12. ブラウザのLambdaタブに戻り、「Add trigger」をクリックします。

13. 「Select a trigger」をクリックしてEventBridgeを検索し、Ruleドロップダウンから「Create a new rule」をクリックします。
ルールに名前と説明を入力します。
「Rule type」でEvent patternのラジオボタンを選択します。
1つ目のドロップダウンでEC2、2つ目のドロップダウンでAWS API call via CloudTrailを選択します。

14. 下にスクロールしてOperationのチェックボックスをオンにし、Operation欄にRunInstancesと入力します。Addボタンをクリックすると、イベントトリガーが作成されます。

15. 最後に、テスト用インスタンスをデプロイして動作を確認します。
数秒後、実装したLambda関数がインスタンスとボリュームを自動でタグ付けします。
ページを更新して、インスタンスのタグを確認してみましょう。

補足
- このソリューションでタグ付けされるのは、Lambda関数を導入した後に新規作成されたインスタンスのみです。
- CloudTrailのtrailを有効にした直後は、EventBridgeが関数を呼び出し始めるまで最大1時間ほどかかることがあります。
- CloudTrailのレスポンスサイズは500KBに制限されています。1回のAPIコールで大量のインスタンスを起動した場合、Lambda関数がすべてのインスタンスにタグを付けきれないことがあります。
- AWS EventBridgeはリージョン単位のリソースです。複数リージョンを利用している場合は、利用するAWSリージョンごとにこのソリューションをデプロイする必要があります。