VPC を云々する CloudFormation なテンプレ
ざくっと作ってみました。基本的には
- NetworkACL は使わない
- サブネットは四つ
- public 一つと private 三つ
- 二つの private は multi AZ な実装で RDS を配置できるように
- ELB も投入
- SecurityGroup でアクセス制限
- public なセグメントに踏台と nat なサーバがある形
- outbound は基本スルー
- memcached な 11211 ポートを云々
- SecurityGroup については作成したのみ
- 別途 ELB や EC2 なインスタンスに割り当てる
みたいな形。あ、あと SecurityGroup 書いてる時に
- 複数の項目なアクセス制限を表現するために配列を使っている
- icmp もポート指定必須
なあたりで微妙にハマりました。あと、現時点で理解できてる範囲で必要な記述 (?) を以下に列挙してみます。
- VPC の定義 (AWS::EC2::VPC)
- InternetGateway の定義と VPC との関連付け (AWS::EC2::VPCGatewayAttachment)
- サブネットの定義 (AWS::EC2::Subnet)
- ルーティングテーブル関連
- AWS::EC2::Routetable を作って VPC と関連付け
- AWS::EC2::Route を作って RouteTable と関連付け
- AWS::EC2::SubnetRouteTableAssociation で Routetable と Subnet を関連付け
- SecurityGroup 関連
- VPC と関連付け
- SecurityGroupIngress (inbound 通信設定)、SecurityGroupEgress (outbound 通信設定) を作る
- 配列が関連付けられます
- 要素の属性としては IpProtocol (必須)、FromPort、ToPort、CidrIp などがあります
なんとなく今時点で雛形っぽくなってるのは以下なソレ。
{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Template vpc_multiple_subnets.", "Resources" : { "VPC" : { "Type" : "AWS::EC2::VPC", "Properties" : { "CidrBlock" : "10.0.0.0/16", "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Public" } ] } }, "PublicSubnet" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "AvailabilityZone" : "ap-northeast-1a", "CidrBlock" : "10.0.0.0/24", "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Public" } ] } }, "InternetGateway" : { "Type" : "AWS::EC2::InternetGateway", "Properties" : { "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Public" } ] } }, "AttachGateway" : { "Type" : "AWS::EC2::VPCGatewayAttachment", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "InternetGatewayId" : { "Ref" : "InternetGateway" } } }, "PublicRouteTable" : { "Type" : "AWS::EC2::RouteTable", "Properties" : { "VpcId" : {"Ref" : "VPC"}, "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Public" } ] } }, "PublicRoute" : { "Type" : "AWS::EC2::Route", "Properties" : { "RouteTableId" : { "Ref" : "PublicRouteTable" }, "DestinationCidrBlock" : "0.0.0.0/0", "GatewayId" : { "Ref" : "InternetGateway" } } }, "PublicSubnetRouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "PublicSubnet" }, "RouteTableId" : { "Ref" : "PublicRouteTable" } } }, "PrivateSubnet" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "AvailabilityZone" : "ap-northeast-1a", "CidrBlock" : "10.0.1.0/24", "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Private" } ] } }, "PrivateRouteTable" : { "Type" : "AWS::EC2::RouteTable", "Properties" : { "VpcId" : {"Ref" : "VPC"}, "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Private" } ] } }, "PrivateSubnetRouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "PrivateSubnet" }, "RouteTableId" : { "Ref" : "PrivateRouteTable" } } }, "DatabaseSubnet1" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "AvailabilityZone" : "ap-northeast-1a", "CidrBlock" : "10.0.2.0/24", "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Database1" } ] } }, "DatabaseRouteTable" : { "Type" : "AWS::EC2::RouteTable", "Properties" : { "VpcId" : {"Ref" : "VPC"}, "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Database1" } ] } }, "DatabaseSubnet1RouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "DatabaseSubnet1" }, "RouteTableId" : { "Ref" : "DatabaseRouteTable" } } }, "DatabaseSubnet2" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "AvailabilityZone" : "ap-northeast-1b", "CidrBlock" : "10.0.3.0/24", "Tags" : [ {"Key" : "Application", "Value" : { "Ref" : "AWS::StackId"} }, {"Key" : "Network", "Value" : "Database2" } ] } }, "DatabaseSubnet2RouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "DatabaseSubnet2" }, "RouteTableId" : { "Ref" : "DatabaseRouteTable" } } }, "ElasticLoadBalancer" : { "Type" : "AWS::ElasticLoadBalancing::LoadBalancer", "Properties" : { "SecurityGroups" : [ { "Ref" : "LoadBalancerSecurityGroup" } ], "Subnets" : [ { "Ref" : "PublicSubnet" } ], "Listeners" : [ { "LoadBalancerPort" : "80", "InstancePort" : "80", "Protocol" : "HTTP" } ], "HealthCheck" : { "Target" : "HTTP:80/", "HealthyThreshold" : "3", "UnhealthyThreshold" : "5", "Interval" : "90", "Timeout" : "60" } } }, "SSHSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "FUMIDAI", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "-1", "CidrIp" : "10.0.0.0/24" }, { "IpProtocol" : "-1", "CidrIp" : "10.0.1.0/24" }, { "IpProtocol" : "-1", "CidrIp" : "10.0.2.0/24" }, { "IpProtocol" : "-1", "CidrIp" : "10.0.3.0/24" }, { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "x.x.x.x/32" }, { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "y.y.y.y/32" } ], "SecurityGroupEgress" : [ { "IpProtocol" : "-1", "CidrIp" : "0.0.0.0/0" } ] } }, "APSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "AP", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "icmp", "FromPort" : "-1", "ToPort" : "-1", "CidrIp" : "0.0.0.0/0" }, { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "10.0.0.0/24" }, { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" }, { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" }, { "IpProtocol" : "tcp", "FromPort" : "11211", "ToPort" : "11211", "CidrIp" : "10.0.1.0/24" } ], "SecurityGroupEgress" : [ { "IpProtocol" : "-1", "CidrIp" : "0.0.0.0/0" } ] } }, "DBSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "RDS", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "3306", "ToPort" : "3306", "CidrIp" : "10.0.0.0/16" }, { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "10.0.0.0/16" } ], "SecurityGroupEgress" : [ { "IpProtocol" : "-1", "CidrIp" : "0.0.0.0/0" } ] } }, "LoadBalancerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP access on port 80", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ], "SecurityGroupEgress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ] } } }, "Outputs" : { "URL" : { "Description" : "URL of the website", "Value" : { "Fn::Join" : [ "", [ "http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]]} } } }
Github 方面にも放り込んでおくかどうするか。
あ、あと validate なナニを以下に控え。
require 'yaml' require 'json' require 'aws-sdk' config_file = File.join(File.dirname(__FILE__), "../config.yml") config = YAML.load(File.read(config_file)) AWS.config(config) cfm = AWS::CloudFormation.new template_file = File.join(File.dirname(__FILE__), "vpc_multiple_subnet.template") template_json = JSON.parse(File.read(template_file)) cfm.validate_template(template_json)
ファイルの名前とか位置は適当に読みかえて頂ければと。