AWS リソースのタグ規約を考える

AWS での悩みどころのひとつに EC2 インスタンスなど各種リソースの名前などタグをどう設定すべきかという点があります。調べてみても、命名規約的なものが整備されているわけではなく、個々にベスト・プラクティスがまとめられているだけ、というのが現状のようです。

皆様のご意見を参考にしたいという意味もあり、命名規約案を公開してみることにしました。こうした方がよいなど、ご意見があれば、コメント頂けると幸いです。

[2019/04/02 追記] user: プレフィクスはコスト配分レポートに表示されるときに付与されるものであり、タグ規約に含めるのは不適切であることに気付きましたので、該当の記述は削除しました。

## 参考となる資料

AWS が正式に公開している資料としては次のものがあります。

- [AWS Tagging Strategies](https://aws.amazon.com/jp/answers/account-management/aws-tagging-strategies/?nc1=h_ls)
- [Amazon EC2 リソースのタグ付けの推奨ベストプラクティスをいくつか紹介してください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-resource-tags/)

ブログ記事では、次のものを参考にさせていただきました。

- [AWS EC2 Tagging — An Overview](https://www.threatstack.com/blog/aws-ec2-tagging-an-overview-2)
- [A guide to tagging resources in AWS](https://medium.com/stax-blog/a-guide-to-tagging-resources-in-aws-8f4311afeb46)

## キーの命名規約

キー名は、次のルールに従います。

- Upper Camel Case 記法[^ucc]とします。（例: BuildId）
- 標準化されていないタグキーには *namespace*: を付与します。namespace は Lower Camel Case 記法[^lcc]とします。（例: projA:CostCenter）

[^ucc]: 英数小文字を英大文字で区切る手法（例: XxxXxxXxx）
[^lcc]: 先頭が英小文字となる Camel Case 記法（例: xxxXxxXxx）

なお、namespace として aws は予約されており、user も用途が決まっているため自由に使うことはできません（後述）。

残念なことに AWS が利用/生成しているキーの名前はすでに一貫性がないため、上記のルールが適用できません。AWS が利用/生成するキーには次のようなものがあります。

|キー名|用途|
|---|---|
|Name|リソースの表示名として使われます。|
|aws:createdBy|AWS Billing and Cost Management にて [AWS 生成コスト配分タグ](https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/aws-tags.html)として付与されます。|
|aws:cloudformation:logical-id|CloudFormation で作成されたリソースに自動付与されます。|
|aws:cloudformation:stack-id|CloudFormation で作成されたリソースに自動付与されます。|
|aws:cloudformation:stack-name|CloudFormation で作成されたリソースに自動付与されます。|

## 値の命名規約

タグの値は次のルールに従って設定します。

- ブール型である値は true あるいは false を設定します。
- 数値型である値は、符号、数値、小数点（および必要に応じて単位）のみからなる値として設定します。表示用にしばしば利用されるカンマ編集や指数表示は使用しません。
- 日付、時刻は ISO 8601 拡張形式で設定します。（例：2001-01-01、01:20:30、2001-01-01T01:20:30、2001-01-01T01:20:30Z）
- その他の値は特に制約を設けず、空白、記号を含む任意の文字列を設定します。

ただし、ひとつのキーに複数の値が紐づくなど構造化する必要がある場合は次のルールに従います。

- 値にサブキーを付ける場合には、イコール記号で区切ります。（例: Title=FooBar）
- 値が複合値（タプル）の場合は、パイプで区切ります。（例: 昭和|S|1926-12-25）
- 複数の値がある場合は、セミコロンで区切ります。（例: value1;value2;value3）

## 標準タグ・キー名

次のものを標準タグとします。これ以外のタグを付与する場合は、namespace を付与するものとします。

### Name（必須）

リソースの表示名です。値の命名は次のルールに従います。

- 値は、Lower Kebab Case[^lkc]とします。これは、ドメイン名やホスト名としても転用できるようするためです。
- 値は、*Stack*-*Environment*-*ResourceType*-*Indentifier* の形式とします。
- Stack には、プロジェクト名など管理単位を設定します。（詳細は Stack タグの項で説明します）
- Environment には、本番や開発など環境名を設定します。（詳細は Environment タグの項で説明します）
- ResourceType には、次のようなリソースの種類を表す略称を設定します。
    - vpc: VPC
    - subnet: サブネット
    - igw: インターネットゲートウェイ
    - nat: NAT ゲートウェイ
    - dopt: DHCP オプション
    - rtb: ルートテーブル
    - sg: セキュリティグループ
    - acl: ネットワーク ACL
    - ec2: EC2 インスタンス
- Identifier には、同じようなリソースが複数ある場合に区別できる名前を設定します。複数の単語から成る場合はハイフンで区切ります。例としては次のようなものがあります。
    - default: デフォルトのリソース
    - public-x: AZ x にあるパブリック・サブネット
    - bastion: 踏み台サーバ
    - ap-1: AP サーバ 1号機
    - db: DB サーバ

[^lkc]: 英数小文字からなる単語をハイフンで区切った記法（例：xxx-xxx-xxx）

### Stack（必須）

リソースの管理単位です。リソースグループのクエリ条件としても利用します。多くの場合、プロジェクト名やシステム名となるでしょう。値の命名は次のルールに従います。

- 英数小文字のみからなる文字列とします。複数単語から成る場合、頭文字をつなげたものや全社共通のシステム ID を使うとよいでしょう。
- VPC などプロジェクトを跨いで共有するものには global を設定します。

Stack は、リソースグループのクエリ条件として使用可能です。

### Environment（必須）

環境名です。リソースグループのクエリ条件としても利用します。原則、次のいずれかを設定します。同じ用途の環境が複数ある場合には末尾に数字を付けて区別します。

- prod: 本番環境
- stage: ステージング環境
- test: テスト環境
- dev: 開発環境
- common: 共有環境

### Service（任意）

デプロイされているサービス名を設定します。例えば、apache、nginx、mysql などです。必要があればハイフンで区切りバージョンを記載しても構いません。（例: apache-2.2.3）

### Version（任意）

デプロイされているアプリケーションのバージョン番号を設定します。

### BuildId（任意）

デプロイされているアプリケーションのビルド時に付与された ID を設定します。

### ManagedBy（任意）

インフラ構築ツールの管理下にあることを示します。値には ansible、terraform などインフラ構築ツールの名前を設定します。

### Owner（任意）

リソースの所有者（所有部署）のコードあるいは名前を設定します。コードと名前を両方記載する場合はパイプ記号で繋いで設定します。

### Project（任意）

リソースの構築元となったプロジェクトのコードあるいは名前を設定します。コードと名前を両方記載する場合はパイプ記号で繋いで設定します。

### Customer（任意）

リソースにより機能が提供される顧客のコードあるいは名前を設定します。コードと名前を両方記載する場合はパイプ記号で繋いで設定します。

### CostCenter（任意）

リソースのコスト負担者（負担部署）コードあるいは名前を設定します。コードと名前を両方記載する場合はパイプ記号で繋いで設定します。

### Role（任意）

リソースの役割を設定します。（例：Web Server、DB Server）

### Contact（任意）

このインフラに関する問い合わせ先メールアドレスを設定します。