AWS 初心者向けハンズオン
「Network編#1 AWS上にセキュアなプライベートネットワーク空間を作成する」をCloudFormationで実施してみました。
目的
- AWS CLIとCloudFormationの実装方法を比較
- スタックの作成、削除はAWS CLIから実施
AWS CLI編はこちら
スタックの作成方法
※TEMPLATE_FILE名, STACK_NAMEは適宜変更
※IAM リソースを含む場合--capabilities CAPABILITY_NAMED_IAM
オプションが必要
TEMPLATE_FILE='~/template/handson_nat.yml'
STACK_NAME=handson
aws cloudformation deploy \
--template-file ${TEMPLATE_FILE} \
--stack-name ${STACK_NAME} \
--capabilities CAPABILITY_NAMED_IAM
スタックの削除方法
※STACK_NAMEは適宜変更
STACK_NAME=handson
aws cloudformation delete-stack \
--stack-name ${STACK_NAME}
テンプレート(NAT編)
handson_nat.yml
AWSTemplateFormatVersion: 2010-09-09
Description: ---
Parameters:
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: "10.0.0.0/16"
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.1.0/24
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.0.2.0/24
PrivateSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.0.11.0/24
PrivateSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 10.0.12.0/24
Resources:
### VPC
handsonVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsHostnames: 'true'
Tags:
- Key: Name
Value: handson
### Subnet_Public
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PublicSubnet1CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Subnet - a"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PublicSubnet2CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Subnet - c"
### Subnet_Private
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PrivateSubnet1CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private subnet - a"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PrivateSubnet2CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private subnet - c"
### Internet Gateway
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: handson-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref handsonVPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Route Table"
DefaultPublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private Route Table"
### RouteTable_Association
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
### SecurityGroup
SecurityGroupPublic:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "beginers-handson SecurityGroup."
GroupName: "beginers-handson-sg"
VpcId: !Ref handsonVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupPrivate:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "ssm"
GroupName: "ssm"
VpcId: !Ref handsonVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Ref VpcCIDR
### EC2用ロール
ec2Role:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'handson-ssm'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- "ec2.amazonaws.com"
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
- 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'
### Create IAM Profile
ec2InstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
InstanceProfileName: handson-ssm
Path: "/"
Roles:
- !Ref ec2Role
### Create Public EC2
PublicEC2:
Type: "AWS::EC2::Instance"
Properties:
AvailabilityZone: ap-northeast-1a
IamInstanceProfile: !Ref ec2InstanceProfile
ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet1
GroupSet:
- !Ref SecurityGroupPublic
UserData:
Fn::Base64: |
#!/bin/bash
yum -y update
yum -y install httpd
systemctl enable httpd.service
systemctl start httpd.service
Tags:
- Key: Name
Value: "Web"
### Create Private EC2
PrivateEC2:
Type: "AWS::EC2::Instance"
Properties:
AvailabilityZone: ap-northeast-1c
IamInstanceProfile: !Ref ec2InstanceProfile
ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "false"
DeviceIndex: "0"
SubnetId: !Ref PrivateSubnet2
GroupSet:
- !Ref SecurityGroupPublic
Tags:
- Key: Name
Value: "Internal"
### NatGateway
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet2
Tags:
- Key: Name
Value: handson-natgateway
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: '0.0.0.0/0'
NatGatewayId: !Ref NatGateway
テンプレート(エンドポイント編)
handson_endpoint.yml
AWSTemplateFormatVersion: 2010-09-09
Description: ---
Parameters:
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: "10.0.0.0/16"
PublicSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.1.0/24
PublicSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.0.2.0/24
PrivateSubnet1CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.0.11.0/24
PrivateSubnet2CIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 10.0.12.0/24
Resources:
### VPC
handsonVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsHostnames: 'true'
Tags:
- Key: Name
Value: handson
### Subnet_Public
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PublicSubnet1CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Subnet - a"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PublicSubnet2CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Subnet - c"
### Subnet_Private
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PrivateSubnet1CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private subnet - a"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: "ap-northeast-1c"
CidrBlock: !Ref PrivateSubnet2CIDR
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private subnet - c"
### Internet Gateway
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: handson-igw
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref handsonVPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Public Route Table"
DefaultPublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref handsonVPC
Tags:
- Key: Name
Value: "Private Route Table"
### RouteTable_Association
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet1
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet2
### SecurityGroup
SecurityGroupPublic:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "beginers-handson SecurityGroup."
GroupName: "beginers-handson-sg"
VpcId: !Ref handsonVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupPrivate:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "ssm"
GroupName: "ssm"
VpcId: !Ref handsonVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: !Ref VpcCIDR
### EC2用ロール
ec2Role:
Type: 'AWS::IAM::Role'
Properties:
RoleName: 'handson-ssm'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- "ec2.amazonaws.com"
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonSSMFullAccess'
- 'arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess'
### Create IAM Profile
ec2InstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
InstanceProfileName: handson-ssm
Path: "/"
Roles:
- !Ref ec2Role
### Create Public EC2
PublicEC2:
Type: "AWS::EC2::Instance"
Properties:
AvailabilityZone: ap-northeast-1a
IamInstanceProfile: !Ref ec2InstanceProfile
ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
SubnetId: !Ref PublicSubnet1
GroupSet:
- !Ref SecurityGroupPublic
UserData:
Fn::Base64: |
#!/bin/bash
yum -y update
yum -y install httpd
systemctl enable httpd.service
systemctl start httpd.service
Tags:
- Key: Name
Value: "Web"
### Create Private EC2
PrivateEC2:
Type: "AWS::EC2::Instance"
Properties:
AvailabilityZone: ap-northeast-1c
IamInstanceProfile: !Ref ec2InstanceProfile
ImageId: "{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}"
InstanceType: t2.micro
NetworkInterfaces:
- AssociatePublicIpAddress: "false"
DeviceIndex: "0"
SubnetId: !Ref PrivateSubnet2
GroupSet:
- !Ref SecurityGroupPublic
Tags:
- Key: Name
Value: "Internal"
### NatGateway
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet2
Tags:
- Key: Name
Value: handson-natgateway
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
# DefaultPrivateRoute:
# Type: AWS::EC2::Route
# Properties:
# RouteTableId: !Ref PrivateRouteTable
# DestinationCidrBlock: '0.0.0.0/0'
# NatGatewayId: !Ref NatGateway
SSMEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: "com.amazonaws.ap-northeast-1.ssm"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !Ref handsonVPC
SubnetIds:
- !Ref PublicSubnet2
SecurityGroupIds:
- !Ref SecurityGroupPrivate
SSMAgentEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.ap-northeast-1.ssmmessages"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !Ref handsonVPC
SubnetIds:
- !Ref PublicSubnet2
SecurityGroupIds:
- !Ref SecurityGroupPrivate
EC2MessageEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.ap-northeast-1.ec2messages"
VpcEndpointType: Interface
PrivateDnsEnabled: true
VpcId: !Ref handsonVPC
SubnetIds:
- !Ref PublicSubnet2
SecurityGroupIds:
- !Ref SecurityGroupPrivate
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: hands-on-beginners-bucket-20240218
s3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub "com.amazonaws.ap-northeast-1.s3"
VpcEndpointType: Gateway
VpcId: !Ref handsonVPC
RouteTableIds:
- !Ref PublicRouteTable
- !Ref PrivateRouteTable
まとめ
ハンズオンをやった上でのCloudFormationで実装のメリット(AWS CLIでの実装と比較)
- テンプレートを作成すれば、環境の作成/削除が楽
- パラメータの値を変えることでIPアドレス等を変えた別環境が簡単に作成できる
- リソースIDの紐づけが簡単
ハンズオンをやった上でのCloudFormationで実装方法、不明点
- エンドポイントのタグ名のつけ方が不明