[アップデート] Amazon Q Developer のルールファイルがサードパーティプラットフォームでも使えるようになったので、Amazon Q Developer for GitHub でためしてみた

[アップデート] Amazon Q Developer のルールファイルがサードパーティプラットフォームでも使えるようになったので、Amazon Q Developer for GitHub でためしてみた

Clock Icon2025.06.29

いわさです。

Amazon Q Developer ではルールファイルを作成しておくことで、ワークスペース内でエージェントが従うべきルールを定義することが出来ます。

https://dev.classmethod.jp/articles/qdev-context-project-rules/

先日のアップデートで、Amazon Q Developer for GitHub と GitLab でも、このルールファイル機能が使えるようになりました。

image.png
Document history for Amazon Q Developer User Guide - Amazon Q Developerより

個人的に、この機能が Amazon Q Developer for GitHub で使えるようになったのは非常にありがたいです。
これまではイシュー内の共通ルールも含めて従うべき情報盛りだくさんで記述する必要があったのですが、この機能が使えるようになったので共通ルールはルールファイルに定義し、イシューの内容は機能開発の本質的な部分にフォーカスさせることが出来ます。

本日は早速 Amazon Q Developer for GitHub で使ってみましたのでその様子を紹介します。

ルールファイルを作成

ルールファイルは Amazon Q Developer IDE の時と同様に.amazonq/rules配下にマークダウン形式で作成します。

https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/third-party-context-project-rules.html

今回は 2 つの GitHub リポジトリを新規作成し、片方にはルールファイルを作成してみます。

AA4967B1-32FA-48B8-9740-CB7E9C4DA5EF_4_5005_c.jpeg

今回は AWS CloudFormation テンプレートを作成するリポジトリを想定し、AWS リソースの命名規則をルールファイルとして定義しておこうと思います。
ルールファイルに定義する内容は次のブログから引っ張ってきてマークダウン形式に変換しました。いつもお世話になっております!

https://dev.classmethod.jp/articles/aws-resource-naming-rule-2024/

ルールファイルはこんな感じになりました。

# AWSリソース命名規則

## 1. 目的

命名規則を定める目的は以下のとおり。

| 目的 | 説明 |
|------|------|
| リソース構成の可視化 | 以下を容易にする<br>- リソースの役割や用途の判別<br>- システム全体の構成把握<br>- リソースの識別性向上による誤操作防止 |
| 運用効率の向上 | 以下の運用作業を効率的に実施する<br>- リソースの検索とフィルタリング<br>- 複数リソースの一括操作<br>- 運用自動化<br>- リソース名の決定 |
| セキュリティ管理の強化 | きめ細かな権限制御 |

> **💡 ポイント**  
> 目的や利用イメージを最初に決めておくと、命名規則の合意形成をスムーズに行えます。

命名規則によって以下の識別を明確にする。

- 対象システム
- 環境 (本番、ステージング、開発など)
- AWS リソース
- 役割
- 用途

## 2. AWSリソースの命名規則

### 2.1. 命名規則の基本ルール

命名規則の基本ルールは以下のとおり。

- 単語間はハイフン (`-`) で結ぶ
- ハイフンが使用できない場合はアンダースコア (`_`)を使用する
- 英小文字と数字のみを使用
- 原則、マルチバイト文字、英大文字、アンダースコア (`_`)、その他の記号は使用しない
- 原則、`{System}-{Env}-{ResourceType}-{Summary}`というフォーマットに沿った名前を付与する

#### 命名規則の各要素

| 要素 | 詳細 |
|------|------|
| **System** | このリソースによって構成されるシステム名<br>本プロジェクトでは`example`を使用する |
| **Env** | リソースの環境名<br>- 本番環境 : `prod`<br>- 本番DR環境 : `proddr`<br>- ステージング環境 : `stg`<br>- ステージングDR環境:`stgdr`<br>- 開発環境 : `dev`<br><br>複数環境で共通的に使用するリソースは重要度の最も高いリソースの環境名を使用する<br>例:本番環境と本番DR環境、ステージング環境で共通的に使用するリソース → `prod` |
| **ResourceType** | リソースの種類を表す略語<br>リソースIDの先頭に付けられているもの、もしくはARNのresource-type、serviceに該当する<br><br>例:<br>- `sg-1234567890ab``sg`<br>- `arn:${Partition}:iam::${Account}:role/${RoleNameWithPath}``role`<br>- `arn:${Partition}:ec2:${Region}:${Account}:instance/${InstanceId}``ec2`<br><br>場合によっては複数単語で構成される<br>例:`tgw-attach-1234567890ab``tgw-attach`<br><br>長いものや分かりにくいものは分かりやすい名前を付与する<br>例:<br>- `elasticloadbalancing``alb`<br>- `autoScalingGroup``asg` |
| **Summary** | リソースの役割、要旨を表す短い文言を任意で記述する<br>SubnetTypeやRole、Usageなど細かく分類される |

#### Summaryの詳細分類

| 分類 | 説明 ||
|------|------|-----|
| **SubnetType** | サブネットの種類<br>- インターネットとインバウンド/アウトバウンドでルーティング可能 → `public`<br>- インターネットへアウトバンドでルーティング可能 → `private`<br>- インターネットとのルーティング不可 → `isolated` | |
| **Role** | リソースの機能的な役割<br>例:Webサーバ → `web`、DBサーバ → `db`<br><br>複数単語の場合はハイフン(-)で結ぶ<br>例:Web管理サーバ → `web-admin` | |
| **Usage** | リソースの用途<br>例:<br>- 各種エンドポイント配置用 → `endpoint`<br>- オンプレミスとVPC間通信管理用 → `ns` (North-South)<br>- VPC間通信管理用 → `ew` (East-West)<br>- SMBクライアント用 → `smb-client` | |
| **AzId** | AZ IDの末尾<br>例:`apne1-az1``az1`<br><br>複数リージョンにデプロイさせActive/Activeで動作させるリソースの場合はAZ IDをそのまま使用することを検討する | |
| **Site** | 接続拠点名<br>例:東京拠点 → `tokyo` | |

#### 表記する情報の順番について

表記する情報の順番としては以下のパターンがある:

1. `{System}-{Env}-{Summary}-{ResourceType}`
2. `{System}-{Env}-{ResourceType}-{Summary}`
3. `{Env}-{System}-{ResourceType}-{Summary}`

**推奨:`{System}-{Env}-{ResourceType}-{Summary}`**

理由:
- 新しい属性を追加する場合の拡張性が良い
- 情報は途中に挿入するより、後ろから追加する方が管理しやすい
- 複数のリソースタイプについて言及する際の認識齟齬を防げる

#### 省略を検討する場面

| 要素 | 省略を検討する場面 |
|------|-------------------|
| **System** | - AWS アカウントがシステム単位で分離されており、リソース情報をマルチアカウントで集約した際に、リソース名に含まれるシステム名をキーとして処理を行わない場合<br>- 一時的な検証用のAWSアカウントであり、短期間でAWSアカウントをクローズする場合<br>- 個人検証用のAWSアカウントであり、他メンバーと共有する必要がない場合 |
| **Env** | - AWS アカウントが環境単位で分離されており、リソース情報をマルチアカウントで集約した際に、リソース名に含まれる環境名をキーとして処理を行わない場合<br>- 一時的な検証用のAWSアカウントであり、短期間でAWSアカウントをクローズする場合<br>- 個人検証用のAWSアカウントであり、他メンバーと共有する必要がない場合 |
| **ResourceType** | - 省略としたとしても、チーム内でのコミュニケーションやドキュメント上で、リソースの種類が文脈から明確に理解できる場合<br>- リソース名の文字数を極力少なくしたい場合<br>- 一時的な検証用のAWSアカウントであり、短期間でAWSアカウントをクローズする場合<br>- 個人検証用のAWSアカウントであり、他メンバーと共有する必要がない場合 |

> **⚠️ 注意**  
> 命名規則を守るために実装コストや管理運用コストが高くなると本末転倒です。物理名を指定した方がトータルで見た時にメリットが大きい場合は物理名を指定しましょう。

### 2.2. 命名規則の適用例外

上述の命名規則の基本ルールの適用範囲外は以下のとおり:

| 適用範囲外のリソースの条件 ||
|---------------------------|-----|
| AWSのリソース以外 | - Amazon FSx for NetApp ONTAPのSnapshot Policy |
| 階層構造で名前付けを行うことが一般的なリソース | - CloudWatch Logsロググループ<br>- SSM Parameter Store<br>- Secrets Manager |
| 命名規則に制約がある場合 | - AWS WAFのログの出力先とするS3バケット名 |
| 自動で作成されるリソース | - Service-Linked Role<br>- EC2インスタンスやRDS DBインスタンスのENI<br>- EC2インスタンスのEBSボリューム |
| 以下条件に当てはまる、あるリソースに従属しているリソース<br>- 単独では存在できない<br>- 親リソースの削除と共に自動的に削除される<br>- 親リソースの一部として管理される<br>- 親リソースは一つのみであり、複数の親リソースから参照されない | - IAMロールのインラインポリシー<br>- S3のライフサイクルルール |
| デフォルトで作成されるリソース | - Security Group<br>- NACL<br>- DHCP Options Set |
| バックアップ | - EBSスナップショット<br>- RDS DBスナップショット<br>- AMI |
| 名前の設定を行うのに設定コストがかかるリソース | - AWS CDK L2 ConstructでDefault Construct以外に自動作成されるリソース |
| そのリソース名をベースに検索、管理しないと思われるリソース | - VPC Flow Logs |

### 2.3. リソースごとの設定例

| AWSリソース | 命名規則 || 文字数上限 | 作成後の名前の変更 | 備考 |
|-------------|----------|-----|-----------|-------------------|------|
| **VPC** | `{System}-{Env}-vpc` | `example-prod-vpc` | 255文字 (タグの上限) || |
| **Subnet** | `{System}-{Env}-subnet-{SubnetType}-{Usage}-{AzId}` | `example-prod-subnet-private-endpoint-az1` | 255文字 (タグの上限) || |
| **Route Table** | `{System}-{Env}-rtb-{SubnetType}-{Usage}-{AzId}` | `example-prod-rtb-private-endpoint-az1` | 255文字 (タグの上限) || 各AZのサブネットごとにルートテーブルを分割しないのであれば、`{AzId}`は不要 |
| **Security Group** | `{System}-{Env}-sg-{SubSystem}-{Role}-{ResourceType}` | `example-prod-sg-nextcloud-web-ec2` | 255文字 | 不可 | |
| **Network ACL** | `{System}-{Env}-acl` | `example-prod-acl` | 255文字 (タグの上限) || |
| **DHCP option sets** | `{System}-{Env}-dopt` | `example-prod-dopt` | 255文字 (タグの上限) || |
| **Internet Gateway** | `{System}-{Env}-igw` | `example-prod-igw` | 255文字 (タグの上限) || |
| **NAT Gateway** | `{System}-{Env}-natgw-{AzId}` | `example-prod-natgw-az1` | 255文字 (タグの上限) || |
| **Elastic IP** | `{System}-{Env}-eip-(natgw-{AzId}\|nlb)` | `example-prod-eip-natgw-az1` | 255文字 (タグの上限) || |
| **VPC Endpoint** | `{System}-{Env}-vpce-{Service}-(interface\|gateway\|resource\|sn)` | `example-prod-vpce-logs` | 255文字 (タグの上限) || `(interface\|gateway\|resource\|sn)`はお好みで |
| **Managerd Prefix List** | `{System}-{Env}-pl-{Usage}` | `example-prod-pl-smb-client` | 255文字 || |
| **Transit Gateway** | `{System}-{Env}-tgw` | `example-prod-tgw` | 255文字 (タグの上限) || |
| **Transit Gateway attachment** | `{System}-{Env}-tgw-attach-(vpc\|vpn-{Site}\|dxgw-{Site})` | `example-prod-tgw-attach-vpn-tokyo` | 255文字 (タグの上限) || `{System}-{Env}`はTransit Gateway attachmentの接続先リソースのものを使用 |
| **Transit Gateway route table** | `{System}-{Env}-tgw-rtb-{Usage}` | `example-prod-tgw-rtb-ns-ew` | 255文字 (タグの上限) || `{Usage}`は通信の関係性を指す |
| **Customer Gateway** | `{System}-{Env}-cgw-{Site}` | `example-prod-cgw-tokyo` | 255文字 (タグの上限) || |
| **Site-to-Site VPN** | `{System}-{Env}-vpn-{Site}` | `example-prod-vpn-tokyo` | 255文字 (タグの上限) || |
| **Direct Connect Gateway** | `{System}-{Env}-dxgw-{Site}` | `example-prod-dxgw-tokyo` | 100文字 || |
| **RAM** | `{System}-{Env}-ram` | `example-prod-ram` | 255文字 (タグの上限) || |
| **EC2 Instance** | `{System}-{Env}-ec2-{SubSystem}-{Role}` | `example-prod-ec2-nextcloud-web` | 255文字 (タグの上限) || Auto Scailingを使わないクラスター構成の場合EC2インスタンス毎に末尾に連番を付与する (`-001``-002`など) |
| **Auto Scaling Group** | `{System}-{Env}-asg-{SubSystem}-{Role}` | `example-prod-asg-nextcloud-web` | 255文字 | 不可 | |
| **起動テンプレート** | `{System}-{Env}-lt-{SubSystem}-{Role}` | `example-prod-lt-nextcloud-web` | 128文字 | 不可 | |
| **Key Pair** | `{System}-{Env}-keypair-{SubSystem}-{Role}` | `example-prod-kerypair-newxcloud-web` | 255文字 | 不可 | |
| **ELB** | `{System}-{Env}-(alb\|nlb\|gwlb)-{SubSystem}-{Role}` | `example-prod-alb-newxcloud-web` | 32文字 | 不可 | 複数のサブシステムでALBを共有する場合は`{SubSystem}-{Role}`は不要 |
| **ELB Target Group** | `{System}-{Env}-elb-tg-{SubSystem}-{Role}` | `example-prod-elb-tg-newxcloud-web` | 32文字 | 不可 | |
| **ACM** | `{System}-{Env}-acm-{SubSystem}` | `example-prod-acm-nextcloud-web` | 255文字 (タグの上限) || |
| **S3 Bucket** | `{System}-{Env}-bucket-{Usage}-{AccountId}` | `example-prod-bucket-vpc-flowlogs-123456780012` | 63文字 | 不可 | 公開するS3バケットには`{AccountId}`を付与しない |
| **IAM Role** | `{System}-{Env}-role-{SubSystem}-{Role}` | `example-prod-role-nextcloud-web` | 64文字 | 不可 | |
| **RDS DB Instance / Aurora DB Insance** | `{System}-{Env}-rds-{SubSystem}` | `example-prod-rds-nextcloud` | 63文字 || 変更する際はRDS DBインスタンスの再起動が必要 |
| **RDS DB Cluster / Aurora DB Clusetr** | `{System}-{Env}-rds-cluster-{SubSystem}` | `example-prod-rds-cluster-nextcloud` | 63文字 || 変更する際はRDS DBインスタンスの再起動が必要 |
| **RDS Subnet Group** | `{System}-{Env}-rds-subgrp` | `example-prod-rds-subgrp` | 255文字 | 不可 | |
| **RDS Parameter Group** | `{System}-{Env}-rds-pg-{SubSystem}` | `example-prod-rds-pg-nextcloud` | 255文字 | 不可 | |
| **RDS Cluster Parameter Group** | `{System}-{Env}-rds-cluster-pg-{SubSystem}` | `example-prod-rds-cluster-pg-nextcloud` | 255文字 | 不可 | |
| **RDS Option Group** | `{System}-{Env}-rds-og-{SubSystem}` | `example-prod-rds-og-nextcloud` | 255文字 | 不可 | |
| **FSxN File system** | `{System}-{Env}-fsxn` | `example-prod-fsxn` | 255文字 (タグの上限) || |
| **FSxN SVM** | `{System}-{Env}-svm-{SubSystem}` | `example-prod-svm-general` | 47文字 | 不可 | |
| **FSxN Volume** | `{System}{Env}_fsvol_{SubSystem}{JunctionPath}` | `example_prod_fsvol_general_poc` | 203文字 || `{JunctionPath}`はボリュームのジャンクションパス<br>ジャンクションパスに含まれる`/``_`に置換 |
| **EFS File system** | `{System}-{Env}-efs-{SubSystem}-{Role}-{Usage}` | `example-prod-efs-nextcloud-web-contents` | 255文字 (タグの上限) || |
| **KMS** | `{System}-{Env}-key-{SubSystem}` | `example-prod-key-nextcloud` | 256文字 (タグおよびエイリアスの上限) | エイリアスは不可 | |
| **AWS WAF** | `{System}-{Env}-webacl-{SubSystem}` | `example-prod-webacl-nextcloud` | 128文字 | 不可 | サブシステムでまとめて使用する場合は`{SubSystem}`を省略 |
| **AWS Backup Vault** | `{System}-{Env}-backup-vault-{SubSystem}` | `example-prod-backup-vault-nextcloud` | 50文字 | 不可 | サブシステムでまとめて使用する場合は`{SubSystem}`を省略<br>同一サブシステム内であっても役割によってWORM機能を使用したい場合は末尾に`{Role}`を付与する |
| **AWS Backup Plan** | `{System}-{Env}-backup-plan-{SubSystem}` | `example-prod-backup-plan-nextcloud` | 50文字 | 不可 | サブシステムでまとめて使用する場合は`{SubSystem}`を省略<br>同一サブシステム内であっても役割によって取得開始時刻や保持期間、コピー有無によって異なる場合は末尾に`{Role}`を付与する |
| **AWS Backup Selection** | `{System}-{Env}-backup-selection-{SubSystem}` | `example-prod-backup-selection-nextcloud` | 50文字 | 不可 | サブシステムでまとめて使用する場合は`{SubSystem}`を省略<br>同一サブシステム内であっても役割によって取得開始時刻や保持期間、コピー有無によって異なる場合は末尾に`{Role}`を付与する |
| **CloudWatch Alarm** | `{System}-{Env}-alarm-{ResourceType}-{SubSystem}-{Role}-{MetricName}` | `example-prod-alarm-fsvol-general-poc-StorageCapacityUtilization` | 255文字 | 不可 | |
| **SNS Topic** | `{System}-{Env}-sns-{SubSystem}-{Usage}` | `example-prod-sns-nextcloud-warning-alarm` | 256文字 | 不可 | サブシステムでまとめて使用する場合は`{SubSystem}`を省略 |

> **💡 ポイント**  
> 作成するリソースの種類ごとに例を追加しておくと、ブレが少ないでしょう。リソースによっては32文字や50文字など名前が長すぎると付与できないことが起こりえます。リソース名に全ての情報を盛り込む必要はありません。過剰になるのではなく、必要十分となるように設定しましょう。

## 3. タグ

上記で定めた規則は各種タグの値として設定する。

運用性向上のため以下のタグを全リソースに共通で付与する。

| タグキー | タグ値 | 備考 |
|----------|--------|------|
| **Name** | `{System}-{Env}-{ResourceType}-{Summary}` | 命名規則で定めたリソース名称<br>※ 「2.2. 命名規則の適用例外」に当てはまるリソースには上述のタグを付与しない |
| **Env** | `(prod\|proddr\|stg\|stgdr)` | 環境名<br>- 本番環境 : `prod`<br>- ステージング環境 : `stg`<br>- 本番DR環境 : `proddr`<br>- ステージングDR環境 : `stgdr` |
| **System** | `example` | システムを識別可能な文字列 |
| **SubSystem** | `example` | サブシステムを識別可能な文字列 |
| **Project** | `project` | プロジェクトを識別可能な文字列 |
| **CmBillingGroup** | `project` | クラスメソッドポータルサイトでコスト分析に使用する |

> **⚠️ 注意**  
> ガチガチなルールを作ると、あとで設定や管理をするのが大変になったりするので、無理のない範囲で定義しましょう。

### 自動化用タグ

何らかの処理を自動化している場合はタグを活用し、対象システムやタスク実行時間を制御する。

| タグキー | タグ値 | 備考 |
|----------|--------|------|
| **BackupSelection** | `example-prod-backup-selection` | AWS Backupによるバックアップ取得管理用タグ<br>AWS BackupのBackup Selectionにて、本タグが付与されたリソースのバックアップを取得するよう設定する |
| **SsmPatchTarget** | `(true\|false)` | SSM Patch Manager適用制御用タグ<br>SSM Patch Managerにてこのタグが付与されてるリソースに対してパッチ適用をするように設定する |
| **SsmHostManagementTarget** | `(true\|false)` | SSM Host Management制御用タグ<br>SSM Quick Setupにてこのタグが付与されてるリソースに対してSSM Agentのアップデートやインベントリ収集をするように設定する |

## 参考情報

- [弊社で使っているAWSリソースの命名規則を紹介します | DevelopersIO](https://dev.classmethod.jp/articles/aws-resource-naming-rule-2024/)
- [AWS リソースのタグ管理 〜タグ付けと統制〜(前編) | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/aws-resource-tagging-management-part1/)
- [AWS リソースのタグ管理 〜タグ付けと統制〜(後編) | Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/aws-resource-tagging-management-part2/)
- [AWSのABAC(タグに基づいたアクセス制御)の設計/運用のポイントを考える | DevelopersIO](https://dev.classmethod.jp/articles/aws-abac-design-operation-points/)
- [AWS タグの活用方法と命名ルールを考える | DevelopersIO](https://dev.classmethod.jp/articles/aws-tag-usage-naming-rule/)
- [ベストプラクティスと戦略 - AWS リソースのタグ付けとタグエディタ](https://docs.aws.amazon.com/ja_jp/ARG/latest/userguide/best-practices-and-strats.html)
- [カテゴリのタグ付け - AWS リソースのタグ付けとタグエディタ](https://docs.aws.amazon.com/ja_jp/ARG/latest/userguide/tag-categories.html)

D5F28213-BDED-4BD9-BF51-9D8D0E85526B.png

イシューを作成してみる

ルールファイルを定義したリポジトリと定義していないリポジトリでそれぞれ同じ内容のイシューを作成し、Amazon Q Developer のラベルを割り当てました。

B934B2CC-99AF-44D1-A40E-B403CAF3C8D1.png

ルールファイルを定義していないリポジトリ

まずはルールのないリポジトリです。
イシューの内容に応じて CloudFormation テンプレートを作成してくれています。細かいルールは定めていないので、そのあたりはお任せな感じです。

C63923C8-0ECC-4CF1-B119-60B78858FD67.png

というか、おそらく最近のアップデートなのか、エージェントの作業状況がリアルタイムにわかるようになってますね。こいつぁ良いや。

そして、作成されたテンプレートがこちら。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Development environment with VPC and EC2 instance'

Parameters:
  EnvironmentName:
    Description: Environment name that is prefixed to resource names
    Type: String
    Default: Dev

  VpcCIDR:
    Description: CIDR block for the VPC
    Type: String
    Default: 10.0.0.0/16

  PublicSubnetCIDR:
    Description: CIDR block for the public subnet
    Type: String
    Default: 10.0.1.0/24

  InstanceType:
    Description: EC2 instance type
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - t2.small
      - t2.medium
    ConstraintDescription: Must be a valid EC2 instance type.

  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: Must be the name of an existing EC2 KeyPair.

  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x.

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-VPC

  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-IGW

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  # Public Subnet
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs '']
      CidrBlock: !Ref PublicSubnetCIDR
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PublicSubnet

  # Public Route Table
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-PublicRouteTable

  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnet

  # Security Group for EC2
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access via port 22
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHLocation
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-EC2-SG

  # EC2 Instance
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: !Ref KeyName
      SubnetId: !Ref PublicSubnet
      ImageId: !Ref LatestAmiId
      Tags:
        - Key: Name
          Value: !Sub ${EnvironmentName}-EC2

  # Latest Amazon Linux 2 AMI
  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Outputs:
  VPC:
    Description: A reference to the created VPC
    Value: !Ref VPC
    Export:
      Name: !Sub ${EnvironmentName}-VPC-ID

  PublicSubnet:
    Description: A reference to the public subnet
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub ${EnvironmentName}-PublicSubnet-ID

  EC2SecurityGroup:
    Description: Security group for the EC2 instance
    Value: !Ref EC2SecurityGroup
    Export:
      Name: !Sub ${EnvironmentName}-EC2-SG-ID

  EC2Instance:
    Description: EC2 Instance ID
    Value: !Ref EC2Instance
    Export:
      Name: !Sub ${EnvironmentName}-EC2-ID

  EC2PublicIP:
    Description: Public IP address of the EC2 instance
    Value: !GetAtt EC2Instance.PublicIp
    Export:
      Name: !Sub ${EnvironmentName}-EC2-PublicIP

  EC2PublicDNS:
    Description: Public DNS of the EC2 instance
    Value: !GetAtt EC2Instance.PublicDnsName
    Export:
      Name: !Sub ${EnvironmentName}-EC2-PublicDNS

CloudFormation として十分成立しているので問題なく動きそうです。
ただ、クラスメソッドでは命名規則やタグ付けをはじめ、それ以外にも品質上の細かい構築ルールが大量に存在しており、このままではお仕事では使えなさそうです。

ルールファイルを定義したリポジトリ

では続いて、ルールファイルを定義したリポジトリでも同じ内容でイシューを作成してみましょう。

A938AC87-5749-484D-9EDB-B154648DCA8E.png

同じような感じで作業が進んでいそうですが、よく見てみるとところどころ命名規則に従って作業を進めている旨が出力されています。良さそうだぞ。

そして出来上がった CloudFormation テンプレートがこちら。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Development environment with VPC and EC2 instance'

Parameters:
  SystemName:
    Type: String
    Default: example
    Description: System name for resource naming
  
  EnvName:
    Type: String
    Default: dev
    Description: Environment name for resource naming (dev, stg, prod)
  
  VpcCidr:
    Type: String
    Default: 10.0.0.0/16
    Description: CIDR block for the VPC
  
  PublicSubnetCidr:
    Type: String
    Default: 10.0.0.0/24
    Description: CIDR block for the public subnet
  
  PrivateSubnetCidr:
    Type: String
    Default: 10.0.1.0/24
    Description: CIDR block for the private subnet
  
  InstanceType:
    Type: String
    Default: t3.micro
    Description: EC2 instance type
    AllowedValues:
      - t2.micro
      - t2.small
      - t3.micro
      - t3.small
  
  KeyPairName:
    Type: String
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Default: ''
  
  SubSystem:
    Type: String
    Default: example
    Description: Subsystem name for resource tagging
  
  Project:
    Type: String
    Default: project
    Description: Project name for resource tagging

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcCidr
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-vpc
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-igw
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Attach Internet Gateway to VPC
  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  
  # Public Subnet
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicSubnetCidr
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-subnet-public-az1
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Private Subnet
  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PrivateSubnetCidr
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-subnet-private-az1
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Public Route Table
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-rtb-public
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Private Route Table
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-rtb-private
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # Public Route
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  
  # Associate Public Subnet with Public Route Table
  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  
  # Associate Private Subnet with Private Route Table
  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable
  
  # Security Group for EC2
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for EC2 instance
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
          Description: Allow SSH access
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
          Description: Allow HTTP access
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-sg-web-ec2
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
  
  # EC2 Instance
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref LatestAmiId
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref EC2SecurityGroup
      KeyName: !If [HasKeyName, !Ref KeyPairName, !Ref 'AWS::NoValue']
      Tags:
        - Key: Name
          Value: !Sub ${SystemName}-${EnvName}-ec2-web
        - Key: Env
          Value: !Ref EnvName
        - Key: System
          Value: !Ref SystemName
        - Key: SubSystem
          Value: !Ref SubSystem
        - Key: Project
          Value: !Ref Project
        - Key: CmBillingGroup
          Value: !Ref Project

  # Latest Amazon Linux 2 AMI
  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2

Conditions:
  HasKeyName: !Not [!Equals [!Ref KeyPairName, '']]

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref VPC
    Export:
      Name: !Sub ${SystemName}-${EnvName}-vpc-id
  
  PublicSubnetId:
    Description: Public Subnet ID
    Value: !Ref PublicSubnet
    Export:
      Name: !Sub ${SystemName}-${EnvName}-public-subnet-id
  
  PrivateSubnetId:
    Description: Private Subnet ID
    Value: !Ref PrivateSubnet
    Export:
      Name: !Sub ${SystemName}-${EnvName}-private-subnet-id
  
  EC2SecurityGroupId:
    Description: Security Group ID for EC2
    Value: !Ref EC2SecurityGroup
    Export:
      Name: !Sub ${SystemName}-${EnvName}-ec2-sg-id
  
  EC2InstanceId:
    Description: EC2 Instance ID
    Value: !Ref EC2Instance
    Export:
      Name: !Sub ${SystemName}-${EnvName}-ec2-instance-id
  
  EC2PublicIP:
    Description: Public IP address of the EC2 instance
    Value: !GetAtt EC2Instance.PublicIp
    Export:
      Name: !Sub ${SystemName}-${EnvName}-ec2-public-ip

これは素晴らしいですね。
冒頭のブログに記載されているルールにかなりしっかり従っているのではないでしょうか。

さいごに

本日は Amazon Q Developer のルールファイルがサードパーティプラットフォームでも使えるようになったので、Amazon Q Developer for GitHub でためしてみました。

前々から Amazon Q Developer for GitHub の出力精度を改善したいと思っていたのですが、これはかなり良いアップデートですね!
Amazon Q Developr for GitHub を使っているプロジェクトが社内でもあるので、早速つかっていきたいと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.