目次
はじめに
本記事ではAWS CDKについて投稿します。
AWS CDKの学習を始めた理由は、以前はCloudFormationを使用してインフラストラクチャを構築していましたがコード量が多くなる、書いていて退屈、テストどうする?アプリのテストみたいにできんの?とか色々課題があったことがAWS CDKを学習するきっかけになりました。
AWS CDKとは(ざっくり)
CDKとはCloud Infrastructure Developer Kitの略でTypeScript、Java、Python、C#、.Net、Go言語などこれらの開発スキルがある該当するプログラミング言語を使用してソースコードでインフラストラクチャを定義します。
ソースコードでインフラストラクチャを構築できれば、同じ環境を複製したいときはマネージメントコンソールからの構築と比較すると遥かに工数を削減することができますし、手動作成から起因するオペレーティングミスの低減も期待ができます。
CDKには多くのメリットがありますが、その中でも私がAWS CDKの魅力を感じたのはユニットテストなどの従来のソフトウェア開発でも使われていたテスト手法がAWS CDKを使用すれば実現可能だということ。せっかくIaCでインフラ構築した後にコンソールで膨大にあるインフラソースを確認するのは割と苦痛だったためこれは期待したいところです。
参考公式ドキュメント : https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/home.html
前提条件
本記事では予め必要な環境が揃っているCloud9を使って進めていきます。
AWS CDKをローカル環境で実行するためには以下に示すものを事前に用意してください。
・AWSアカウントとユーザー
・AWS CLI
・IDE
・Node.js
・IDE
・AWS CDKツールキット
・ご使用になるプログラム言語(TypeScript、Python、Java等)
※ Cloud9のCloudFormationテンプレートをGitHubに置きました。
“practice-operation-cloud9.yaml”をそのままCloudFormationに流すとCloud9を使うことができます。
AWS CDK for Cloud9
※本実施内容を進めるためにご自身のAWSアカウントのVPC内にCloud9が作成されていることが前提となります。
Cloud9では前述したAWS CDKやnpmなど既にインストールされている状態ですのですぐに開発を進めることができます。
試しに確認してみましょう。
$ node --version
Node.jsバージョン確認結果
CDKのバージョン確認
※ CDKコマンド実行時にCloud9を動かしているAmazonLinuxにインストールされているnode.jsのバージョンが古いと怒られていますが、ここは気にせず進めていきます。
CDKプロジェクトの作成
まずはCDK用の空のディレクトリを作成後に作成したディレクトリに移動します。
この時に作成するディレクトリ名がCDKのプロジェクト名になります。
$ mkdir workcdk && cd workcdk
次に”cdk init --lan
guage <CDKで使用できるプログラム言語を指定>” コマンドでプロジェクトを作成します。※ 私はCDKの中でも情報量が多いTypeScriptを使用しています。
$ cdk init --language typescript
実行すると以下の内容が出力され作成したディレクトリにファイル群が自動生成されます。
※自動生成されたファイル群
以下に示すディレクトリとファイルが作成されます。
※ 使用している環境によって異なる場合もあります
workcdk/
├── bin/
│ └── workcdk.ts
├── lib/
│ └── workcdk-stack.ts
├── node_modules/
├── test/
│ └── workcdk.test.ts
├── cdk.json
├── jest.config.js
├── package.json
├── README.md
├── tsconfig.json
VPCを作ってみよう
VPCをCDKで作成するためにはパッケージ ‘aws-cdk-lib/aws-ec2’モジュールをインポートする必要があります。他にCDKアプリケーションモジュールが必要です。VPCはEC2モジュールの仲間であるためVPCを作成するときは’aws-cdk-lib/aws-ec2’モジュールをインポートする必要があるという理解です( ・∇・)
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
[参考] :
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2-readme.html
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib-readme.html
続いてVPCを作成するためにコードを追記していきます。
export class WorkcdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// ここに作成したいリソースを追加する!
});
}
}
コード追加後
export class WorkcdkStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// VPCの作成
const vpc = new ec2.Vpc(this, 'VPC', {
ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
});
}
}
はい、CDKだとこれだけのコードでVPCを作成することができちゃいます!試しにデプロイ、っとその前にコードを保存し”cdk diff”コマンドで差分を比較しましょう(デプロイ前に必ずcdk diffコマンドで確認するようにした方がいいです)。
$ cdk diff
│ Resource │ Effect │ Action │ Principal │ Condition │
├───┼─────────────────────────────────────────────────────────┼────────┼─────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────┼───────────┤
│ + │ ${Custom::VpcRestrictDefaultSGCustomResourceProvider/Ro │ Allow │ sts:AssumeRole │ Service:lambda.amazonaws.com │ │
│ │ le.Arn} │ │ │ │ │
├───┼─────────────────────────────────────────────────────────┼────────┼─────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────┼───────────┤
│ + │ arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::Account │ Allow │ ec2:AuthorizeSecurityGroupEgress │ AWS:${Custom::VpcRestrictDefaultSGCustomResourceProvide │ │
│ │ Id}:security-group/${VPCB9E5F0B4.DefaultSecurityGroup} │ │ ec2:AuthorizeSecurityGroupIngress │ r/Role} │ │
│ │ │ │ ec2:RevokeSecurityGroupEgress │ │ │
│ │ │ │ ec2:RevokeSecurityGroupIngress │ │ │
└───┴─────────────────────────────────────────────────────────┴────────┴─────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────┐
│ │ Resource │ Managed Policy ARN │
├───┼────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${Custom::VpcRestrictDefaultSGCustomResourceProvider/Role} │ {"Fn::Sub":"arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"} │
└───┴────────────────────────────────────────────────────────────┴────────────────────
Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}
Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}
Resources
[+] AWS::EC2::VPC VPC VPCB9E5F0B4
[+] AWS::EC2::Subnet VPC/PublicSubnet1/Subnet VPCPublicSubnet1SubnetB4246D30
[+] AWS::EC2::RouteTable VPC/PublicSubnet1/RouteTable VPCPublicSubnet1RouteTableFEE4B781
[+] AWS::EC2::SubnetRouteTableAssociation VPC/PublicSubnet1/RouteTableAssociation VPCPublicSubnet1RouteTableAssociation0B0896DC
[+] AWS::EC2::Route VPC/PublicSubnet1/DefaultRoute VPCPublicSubnet1DefaultRoute91CEF279
[+] AWS::EC2::EIP VPC/PublicSubnet1/EIP VPCPublicSubnet1EIP6AD938E8
[+] AWS::EC2::NatGateway VPC/PublicSubnet1/NATGateway VPCPublicSubnet1NATGatewayE0556630
[+] AWS::EC2::Subnet VPC/PublicSubnet2/Subnet VPCPublicSubnet2Subnet74179F39
[+] AWS::EC2::RouteTable VPC/PublicSubnet2/RouteTable VPCPublicSubnet2RouteTable6F1A15F1
[+] AWS::EC2::SubnetRouteTableAssociation VPC/PublicSubnet2/RouteTableAssociation VPCPublicSubnet2RouteTableAssociation5A808732
[+] AWS::EC2::Route VPC/PublicSubnet2/DefaultRoute VPCPublicSubnet2DefaultRouteB7481BBA
[+] AWS::EC2::EIP VPC/PublicSubnet2/EIP VPCPublicSubnet2EIP4947BC00
[+] AWS::EC2::NatGateway VPC/PublicSubnet2/NATGateway VPCPublicSubnet2NATGateway3C070193
[+] AWS::EC2::Subnet VPC/PrivateSubnet1/Subnet VPCPrivateSubnet1Subnet8BCA10E0
[+] AWS::EC2::RouteTable VPC/PrivateSubnet1/RouteTable VPCPrivateSubnet1RouteTableBE8A6027
[+] AWS::EC2::SubnetRouteTableAssociation VPC/PrivateSubnet1/RouteTableAssociation VPCPrivateSubnet1RouteTableAssociation347902D1
[+] AWS::EC2::Route VPC/PrivateSubnet1/DefaultRoute VPCPrivateSubnet1DefaultRouteAE1D6490
[+] AWS::EC2::Subnet VPC/PrivateSubnet2/Subnet VPCPrivateSubnet2SubnetCFCDAA7A
[+] AWS::EC2::RouteTable VPC/PrivateSubnet2/RouteTable VPCPrivateSubnet2RouteTable0A19E10E
[+] AWS::EC2::SubnetRouteTableAssociation VPC/PrivateSubnet2/RouteTableAssociation VPCPrivateSubnet2RouteTableAssociation0C73D413
[+] AWS::EC2::Route VPC/PrivateSubnet2/DefaultRoute VPCPrivateSubnet2DefaultRouteF4F5CFD2
[+] AWS::EC2::InternetGateway VPC/IGW VPCIGWB7E252D3
[+] AWS::EC2::VPCGatewayAttachment VPC/VPCGW VPCVPCGW99B986DC
[+] Custom::VpcRestrictDefaultSG VPC/RestrictDefaultSecurityGroupCustomResource VPCRestrictDefaultSecurityGroupCustomResource59474679
[+] AWS::IAM::Role Custom::VpcRestrictDefaultSGCustomResourceProvider/Role CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0
[+] AWS::Lambda::Function Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E
Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}
Number of stacks with differences: 1
ちょっと長いですが、先ほど書いたコードに対して”cdk diff”コマンドで確認すると上記に示されているインフラリソースが構築されるそうです。想定だとVPCのみ作られるはずが、めっちゃ多い?w
“cdk synth”コマンドを使ってCloudFormationテンプレートを生成してみました・:*+.\(( °ω° ))/.:+
Resources:
VPCB9E5F0B4:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: WorkcdkStack/VPC
Metadata:
aws:cdk:path: WorkcdkStack/VPC/Resource
VPCPublicSubnet1SubnetB4246D30:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
CidrBlock: 10.0.0.0/18
MapPublicIpOnLaunch: true
Tags:
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet1
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/Subnet
VPCPublicSubnet1RouteTableFEE4B781:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet1
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/RouteTable
VPCPublicSubnet1RouteTableAssociation0B0896DC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet1RouteTableFEE4B781
SubnetId:
Ref: VPCPublicSubnet1SubnetB4246D30
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/RouteTableAssociation
VPCPublicSubnet1DefaultRoute91CEF279:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGWB7E252D3
RouteTableId:
Ref: VPCPublicSubnet1RouteTableFEE4B781
DependsOn:
- VPCVPCGW99B986DC
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/DefaultRoute
VPCPublicSubnet1EIP6AD938E8:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet1
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/EIP
VPCPublicSubnet1NATGatewayE0556630:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- VPCPublicSubnet1EIP6AD938E8
- AllocationId
SubnetId:
Ref: VPCPublicSubnet1SubnetB4246D30
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet1
DependsOn:
- VPCPublicSubnet1DefaultRoute91CEF279
- VPCPublicSubnet1RouteTableAssociation0B0896DC
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet1/NATGateway
VPCPublicSubnet2Subnet74179F39:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
CidrBlock: 10.0.64.0/18
MapPublicIpOnLaunch: true
Tags:
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet2
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/Subnet
VPCPublicSubnet2RouteTable6F1A15F1:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet2
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/RouteTable
VPCPublicSubnet2RouteTableAssociation5A808732:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet2RouteTable6F1A15F1
SubnetId:
Ref: VPCPublicSubnet2Subnet74179F39
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/RouteTableAssociation
VPCPublicSubnet2DefaultRouteB7481BBA:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGWB7E252D3
RouteTableId:
Ref: VPCPublicSubnet2RouteTable6F1A15F1
DependsOn:
- VPCVPCGW99B986DC
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/DefaultRoute
VPCPublicSubnet2EIP4947BC00:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet2
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/EIP
VPCPublicSubnet2NATGateway3C070193:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- VPCPublicSubnet2EIP4947BC00
- AllocationId
SubnetId:
Ref: VPCPublicSubnet2Subnet74179F39
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PublicSubnet2
DependsOn:
- VPCPublicSubnet2DefaultRouteB7481BBA
- VPCPublicSubnet2RouteTableAssociation5A808732
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PublicSubnet2/NATGateway
VPCPrivateSubnet1Subnet8BCA10E0:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
CidrBlock: 10.0.128.0/18
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
- Key: Name
Value: WorkcdkStack/VPC/PrivateSubnet1
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet1/Subnet
VPCPrivateSubnet1RouteTableBE8A6027:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PrivateSubnet1
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet1/RouteTable
VPCPrivateSubnet1RouteTableAssociation347902D1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPrivateSubnet1RouteTableBE8A6027
SubnetId:
Ref: VPCPrivateSubnet1Subnet8BCA10E0
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet1/RouteTableAssociation
VPCPrivateSubnet1DefaultRouteAE1D6490:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: VPCPublicSubnet1NATGatewayE0556630
RouteTableId:
Ref: VPCPrivateSubnet1RouteTableBE8A6027
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet1/DefaultRoute
VPCPrivateSubnet2SubnetCFCDAA7A:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
CidrBlock: 10.0.192.0/18
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
- Key: Name
Value: WorkcdkStack/VPC/PrivateSubnet2
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet2/Subnet
VPCPrivateSubnet2RouteTable0A19E10E:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: WorkcdkStack/VPC/PrivateSubnet2
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet2/RouteTable
VPCPrivateSubnet2RouteTableAssociation0C73D413:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPrivateSubnet2RouteTable0A19E10E
SubnetId:
Ref: VPCPrivateSubnet2SubnetCFCDAA7A
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet2/RouteTableAssociation
VPCPrivateSubnet2DefaultRouteF4F5CFD2:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: VPCPublicSubnet2NATGateway3C070193
RouteTableId:
Ref: VPCPrivateSubnet2RouteTable0A19E10E
Metadata:
aws:cdk:path: WorkcdkStack/VPC/PrivateSubnet2/DefaultRoute
VPCIGWB7E252D3:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: WorkcdkStack/VPC
Metadata:
aws:cdk:path: WorkcdkStack/VPC/IGW
VPCVPCGW99B986DC:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId:
Ref: VPCIGWB7E252D3
VpcId:
Ref: VPCB9E5F0B4
Metadata:
aws:cdk:path: WorkcdkStack/VPC/VPCGW
VPCRestrictDefaultSecurityGroupCustomResource59474679:
Type: Custom::VpcRestrictDefaultSG
Properties:
ServiceToken:
Fn::GetAtt:
- CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E
- Arn
DefaultSecurityGroupId:
Fn::GetAtt:
- VPCB9E5F0B4
- DefaultSecurityGroup
Account:
Ref: AWS::AccountId
UpdateReplacePolicy: Delete
DeletionPolicy: Delete
Metadata:
aws:cdk:path: WorkcdkStack/VPC/RestrictDefaultSecurityGroupCustomResource/Default
CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
ManagedPolicyArns:
- Fn::Sub: arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: Inline
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:AuthorizeSecurityGroupEgress
- ec2:RevokeSecurityGroupIngress
- ec2:RevokeSecurityGroupEgress
Resource:
- Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- ":ec2:"
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- :security-group/
- Fn::GetAtt:
- VPCB9E5F0B4
- DefaultSecurityGroup
Metadata:
aws:cdk:path: WorkcdkStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Role
CustomVpcRestrictDefaultSGCustomResourceProviderHandlerDC833E5E:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket:
Fn::Sub: cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}
S3Key: 4b996a3e5a083d5c78c6f30a8571a94fb7ec557eecbe54dbc065faba0d9076e6.zip
Timeout: 900
MemorySize: 128
Handler: __entrypoint__.handler
Role:
Fn::GetAtt:
- CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0
- Arn
Runtime: nodejs18.x
Description: Lambda function for removing all inbound/outbound rules from the VPC default security group
DependsOn:
- CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0
Metadata:
aws:cdk:path: WorkcdkStack/Custom::VpcRestrictDefaultSGCustomResourceProvider/Handler
aws:asset:path: asset.4b996a3e5a083d5c78c6f30a8571a94fb7ec557eecbe54dbc065faba0d9076e6
aws:asset:property: Code
長い Σ੧(❛□❛✿)wwww なんだか細かく指定しなくてもサブネットとかインターネットゲートウェイとかも一緒にくっついてくるコンストラクトレベル2のVpcを指定しており、AWSのベストプラクティスに基づいて色々くっついて作成してくれるみたいです。とりあえず細かくは指定しないでざっくりとしたインフラが欲しいときなどのスピードが求められる場合はコンスラクトレベル2は超便利だと思います。細かく指定した場合はコンストラクトレベル3の”Cfn”を先頭にしてVPCなどのリソースを指定する必要があるみたいです。
まあ・・・とりあえずデプロイしてみようと思います_:(´ཀ`」 ∠):
※ AWS CDKを始めてAWSアカウント/リージョンにデプロイする時は “cdk bootstrap”コマンドを実行してください。これはAWS CDKを環境にデプロイするために必要なリソースが含まれたスタックを作成するために必要です。
$ cdk deploy
cdk deployを実行すると以下の追加されるリソースが出力されDeployしてもいいか聞かれるので良かったらYESのy、嫌だったらNoのnを入力します。今回はyで進めます!
※ CDKは直接APIを叩いてるTerraformとは違いTypescriptからコンパイルしてCloudFormationに変換する処理が伴うためデプロイ速度は遅め。
デプロイが完了しました!
AWSマネージメントコンソールからCloudFormationを確認していきます。
このデプロイにより VPC だけじゃなく、サブネット 4 つ、ルートテーブル 4 つ、インターネットゲートウェイ 1 つ、Elastic IP 2 つ、NAT ゲートウェイ “2 つ”も”作成されていました。そんなに頼んでないんだけど今回はコンストラクトの指定に”Vpc”を指定していたため、コンストラクトレベル2ということでAWSベストプラクティスに沿ってよしなに構築してくれたみたいです。
Construct(コンストラクト)とは
AWS CDKコンストラクトとはアプリの基本的な構成要素とのことでVPCやAPIGatewayなどそれぞれがConstruceという単位で提供されています。
例えば、s3.Bucketクラス(Construct)はAmazonS3バケットを、VPCクラス(Construct)はVPCを表します。
また、コンストラクトにはL1 〜 L3と3つの異なるレベルのコンストラクトがあります。
L1 Construct
最下層のクラスでコンストラクトレベル1で構築する場合はVPCやS3などのクラスの前に”Cfn”のプレフィックスを付けてあげて全てのリソースプロパティを明示的に宣言していく必要があります。
L2 Construct
コンストラクトL2になるとL1に比べると抽象的にAWSリソースを指定して作成することができます。
開発者などAWSインフラリソースに知見がない人でもスピーディーにAWSベストプラクティスに沿ったインフラストラクチャ構築を可能とします。
L3 Construct
コンストラクトL3になるとパターンと呼ばれる一般的な構成を事前に定義されているコンストラクトになります。例えば、LambdaRestApiコンストラクトはAWS Lambda関数とAmazon API Gatewayをスピーディに展開する時に使用します。
[参考] : https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/constructs.html
deployしたリソースの削除
最後に本記事で作成したリソースを削除します。今回はコンストラクトL2のVPCを使ってVPCを構築しているため、サブネット 4 つ、ルートテーブル 4 つ、インターネットゲートウェイ 1 つ、Elastic IP 2 つ、NAT ゲートウェイ “2 つ”も作成されています。特にNATゲートウェイは置いておくだけで月3000円程度かかってくるお高いサービスですので消します_:(´ཀ`」 ∠):
作成したCloudFormationスタックを削除するためはターミナルから”cdk destroy”コマンドを実行します。削除していいか” y/n “で聞かれますので迷わず ” y “で実行します。
$ cdk destroy
Are you sure you want to delete: WorkcdkStack (y/n)? y
WorkcdkStack: destroying... [1/1]
current credentials could not be used to assume 'arn:aws:iam::355126125825:role/cdk-hnb659fds-deploy-role-355126125825-ap-northeast-1', but are for the right account. Proceeding anyway.
WorkcdkStack: destroyed
これで綺麗に掃除できたはずです。念の為、AWSマネージメントコンソールを確認しましたがデプロイ直後に生成されていたスタックがCloudFormationから削除されていました。もちろんVPCや付随して作成されていたリソースも削除されていました(便利)。
終わりに
ここまでご覧いただきありがとうございました。 実は私はプログラムコードについては趣味で書く程度であまりプロではないですがAWS CDKを触ることで少しだけお近づきになれた気がしました。特にCloudFormationを書いてる時と比べると”書いてる”よりも”作ってる感覚”があって楽しいと思いました。
このシリーズではAWS CDKについて私自身がインプットしたことをアウトプットする場として活用しながら少しでもAWS CDKの魅力についてお伝えできたらと思います。
【環境】
・ AWS Cloud9
・プログラム言語 : TypeScript