VSCodeを使ってCloudFormationの開発環境を構築する機会がありました。
導入して効果的だったVSCode拡張機能について紹介します。
紹介するのは次の2つです。
- CloudFormation
- cfn-lint
CloudFormation
CloudFormationのテンプレートを効率よく作成するためのツールです。
https://marketplace.visualstudio.com/items?itemName=aws-scripting-guy.cform
テンプレートには含まなければいけない必須のフィールドも存在します。
CloudFormationを初めて書くような時、公式ドキュメントを見ながらそれぞれのフィールドを作っていくことになり、地味に面倒です。
また、不慣れなうちはフォーマットエラーを起こしてしまうこともしばしばあります。
この拡張機能を使うと、一瞬でCloudFormation用の空のテンプレートを作成でき、作成時のエラーを減らすことができます。
使い方は簡単で、空のyamlファイル(jsonでも可)を作成し、「start」と入力してtabキーを押すと空のテンプレートを作成できます。

さらに、リソースごとにも細かく必須フィールドの指定をしなければなりませんが、リソース別のフォーマット作成も簡単に行うことができます。
例えば、「ec2-instance」と入力してtabキーを押すと、次のような必須のフィールド等を含んだ空のテンプレートを作成してくれます。

拡張機能を使う際の注意点として、yaml形式でテンプレートで関数の短縮記法の関数(!Ref 等)を使用すると構文エラーとして認識されてしまいます。
これを防ぐため、VScodeの設定ファイル(settings.json)に次のような記述を追加する必要があります。テンプレートとして使用される短縮記法の関数を指定します。この時、文字列やブーリアンなどではなく、配列やオブジェクトを指定する必要がある関数に対しては、「sequence」や「mapping」といったタイプを指定する必要があります。詳細はこちらを参照ください。
// Custom tags for the parser to use
"yaml.customTags": [
"!And",
"!And sequence",
"!If",
"!If sequence",
"!Not",
"!Not sequence",
"!Equals",
"!Equals sequence",
"!Or",
"!Or sequence",
"!FindInMap sequence",
"!Base64",
"!Base64 mapping",
"!Cidr",
"!Cidr sequence",
"!Ref",
"!Sub",
"!GetAtt",
"!GetAZs",
"!ImportValue",
"!Select",
"!Select sequence",
"!Split",
"!Split sequence",
"!Join sequence"
],
// Enable/disable default YAML formatter (requires restart)
"yaml.format.enable": true,
CloudFormation Linter
CloudFormationのテンプレート解析ツールです。
https://marketplace.visualstudio.com/items?itemName=kddejong.vscode-cfn-lint
テンプレートを書いている最中は書き方に誤りがあっても気が付かず、いざデプロイをしてみて初めて間違っていることに気が付くことはよくあります。
そのような煩わしさを解消してくれる便利なツールです。
例えば、以下の誤りを含むテンプレートを考えます。
# cfnlintdemo/templates/bad-routeable-association.yaml
---
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Bad SubnetRouteTableAssociation'
Parameters:
PublicRouteTable:
Type: String
PrivateRouteTable:
Type: String
PublicSubnet01:
Type: String
PrivateSubnet01:
Type: String
Resources:
PublicSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: {Ref: PublicRouteTable}
SubnetId: {Ref: PublicSubnet01}
PrivateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: {Ref: PrivateRouteTable}
SubnetId: {Ref: PublicSubnet01}
ぱっと見ではどのあたりが間違っているかがわかりにくいですが、cfn-lintの拡張機能をインストールすると、誤りがある箇所を赤い波線で示してくれます。

誤りの箇所にマウスカーソルを合わせると、エラーの原因が表示されます。
表示されたエラーは次のような内容でした。
[cfn-lint] E3022: SubnetId in PublicSubnetRouteTableAssociation1 is also associated with PrivateSubnetRouteTableAssociation1
このとおり、別のルートテーブルもこのサブネットに紐づけられていることが原因のエラーだとすぐにわかりました。
また、黄色の波線がPrivateSubnet1についています。これは、対象のパラメータがどこからも参照されていないことを示す警告です。
本来であれば、PrivateSubnet RouteTableAssociation1にこのサブネットが紐付けられるべきだったわけですね。
cfn-lintにはテンプレートの参照関係をグラフで表示してくれる機能もあります。(※pydotのインストールが別途必要)
EC2インスタンス用のテンプレートサンプルで作成し、グラフ化するとこんな感じになります。

グラフの元になったテンプレートはこちら。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
EC2ImageId:
Type: String
Description: "Specifies the AMI ID for your instances."
AllowIngressCidrIP:
Type: String
Resources:
# IAM Role for EC2
TestIAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: Test-IAM-Role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
# IAM InstanceProfile for EC2
TestIAMInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Roles:
-
!Ref TestIAMRole
## EC2 Security Group
TestEC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: TestEC2SecurityGroup
GroupDescription: TestEC2SecurityGroup
VpcId:
Fn::ImportValue: TestVPC
Tags:
- Key: Name
Value: TestEC2SecurityGroup
## EC2 Security Group Ingress
TestEC2SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref TestEC2SecurityGroup
IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: !Ref AllowIngressCidrIP
## EC2 Launch Template
TestLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: TestLaunchTemplate
LaunchTemplateData:
InstanceType: t2.micro
IamInstanceProfile:
Name: !Ref TestIAMInstanceProfile
ImageId: !Ref EC2ImageId
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: true
SubnetId: !ImportValue TestVPCSubnet
Groups:
- !Ref TestEC2SecurityGroup
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 8
VolumeType: gp3
## EC2 Instance
TestEC2Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref TestLaunchTemplate
Version: !GetAtt TestLaunchTemplate.LatestVersionNumber
Tags:
- Key: Name
Value: TestEC2Instance
他の人が作ったテンプレートを解析する場合などで役立つ機能かもしれません。
まとめ
CloudFormationのテンプレートを作成する時に役立つVScode拡張機能を2つ紹介しました。
機会があれば試してみてください。
コメント