AWS CLIでVPC環境を構築する手順を作ったので公開。変数等は設定ファイルにまとめても良いと思ったけど、命名ルールが揺らいでいる最中に作ったので、敢えて毎度設定する手順とし、また、変数の流し込み方はbash前提。ウィザードから作成すると何が裏で作成されているのかが把握できないので、個別に1つ1つの項目を作成していった方が理解が深まると思います。
構築する環境
構築する環境は以下の通り。詳細は命名ルールから察してください。
項目 | Nameタグ | CIDRブロック | Regin/Availability Zone/他 |
VPC名 | VPC-MySystem | 10.100.0.0/22 | ap-northeast-1 |
Subnet名 | SN-MySystem-Public-1 | 10.100.0.0/24 | ap-northeast-1a |
Subnet名 | SN-MySystem-Private-1 | 10.100.1.0/24 | ap-northeast-1a |
Subnet名 | SN-MySystem-Public-2 | 10.100.2.0/24 | ap-northeast-1c |
Subnet名 | SN-MySystem-Private-2 | 10.100.3.0/24 | ap-northeast-1c |
オンプレNW | オンプレNW | 10.0.0.0/8 | ※VPN接続想定 |
前提
権限のある作業用IAMアカウントとそのアクセスキー作成は割愛。Amazon Linux環境の場合は不要となるが、RHEL系Linux前提のAWS CLI環境のセットアップ手順も記載しておく。OSX環境はこちらも参考にしてください。
# pythonは2.6以降? # python, python-setuptoolsを導入 sudo yum install python python-setuptools -y # pip install easy_install pip # awscli install pip install awscli # version確認(ここのところupdateが続いていて本日時点は1.6.4が最新) aws --version # アクセスキー情報登録 aws configure AWS Access Key ID [****************WZCA]:(アクセスキーID) AWS Secret Access Key [****************u0qi]:(シークレットアクセスキー) Default region name [ap-northeast-1]:(Tokyoリージョンを想定) Default output format [json]:(以降の手順はjson出力がデフォルトの想定)
元々、credentialsはAWS SDK用、configはAWS CLI用だったと思うのだけど、AWS CLIの最近のバージョンはアクセスキー、シークレットアクセスキーをcredentialsに、リージョンとアウトプットをconfigに保存するようになった模様。
$ cat ~/.aws/config [default] output = json region = ap-northeast-1 $ cat ~/.aws/credentials [default] aws_access_key_id = ****************WZCA aws_secret_access_key = ****************u0qi
ちなみに認証情報は下記順序で参照されることに注意。実は環境変数が最強なので、aws configureした情報をOverrideすることもできる。
- Environment Variables(環境変数)
- ~/.aws/credentials,C:\Users\USERNAME\.aws\credentials
- ~/.aws/config,C:\Users\USERNAME\.aws\config
- Instance profile credentials(インスタンスに割り当てたIAM Role)
利用できる環境変数や指定可能な共通オプションはこちらを参考にすると良い。
Variable | Option | Config Entry | Environment Variable | Description |
---|---|---|---|---|
profile | –profile | profile | AWS_DEFAULT_PROFILE | Default profile name |
region | –region | region | AWS_DEFAULT_REGION | Default AWS Region |
config_file | AWS_CONFIG_FILE | Alternate location of config | ||
output | –output | output | AWS_DEFAULT_OUTPUT | Default output style |
access_key | aws_access_key_id | AWS_ACCESS_KEY_ID | AWS Access Key | |
secret_key | aws_secret_access_key | AWS_SECRET_ACCESS_KEY | AWS Secret Key | |
token | aws_security_token | AWS_SECURITY_TOKEN | AWS Token (temp credentials) |
方針
jqは使用せず、AWS CLIで利用できるオプションをできる限り利用した。作成したものには全てNameタグを付与する方針としたので、悩んだ挙句awkコマンドを利用することにした。
- jqは使わない(できる限りAWS CLIで)
- createしたらすぐにNameタグをすぐにつける
- awkコマンドを使うことは許容
各オブジェクトの作成フローは以下の通り。
- 名前等を変数で指定(exportは念の為。bash環境想定。)
- createと同時にID取得
- 作成したオブジェクトに応じて必要な初期設定
- describe系コマンドで情報出力
- 再作成を考慮して削除手順を「###」付きで記載
1. VPC作成
# 変数定義 export CIDR=10.100.0.0/22 export VPCNAME=VPC-MySystem # VPC作成 export VPCID=$(aws ec2 create-vpc --cidr-block $CIDR | awk '/VpcId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $VPCID --tags Key=Name,Value=$VPCNAME # VPC Attribute設定 ※DNS Hostnames設定を忘れがちなので注意 aws ec2 modify-vpc-attribute --vpc-id $VPCID --enable-dns-support aws ec2 modify-vpc-attribute --vpc-id $VPCID --enable-dns-hostnames # describeで確認 aws ec2 describe-vpcs --vpc-ids $VPCID aws ec2 describe-vpc-attribute --vpc-id $VPCID --attribute enableDnsSupport aws ec2 describe-vpc-attribute --vpc-id $VPCID --attribute enableDnsHostnames # 削除手順 ###export VPCID=$(aws ec2 describe-vpcs --query Vpcs[].VpcId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$VPCNAME" --output text) ###aws ec2 delete-vpc --vpc-id $VPCID
2. Internet Gateway作成
# 変数定義 export IGWNAME=IGW-MySystem # Internet Gateway作成 export IGWID=$(aws ec2 create-internet-gateway | awk '/InternetGatewayId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $IGWID --tags Key=Name,Value=$IGWNAME # VPCに割り当て aws ec2 attach-internet-gateway --internet-gateway-id $IGWID --vpc-id $VPCID # describeで確認 aws ec2 describe-internet-gateways --filters "Name=internet-gateway-id,Values=$IGWID" # 削除手順 ###export IGWID=$(aws ec2 describe-internet-gateways --query InternetGateways[].InternetGatewayId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$IGWNAME" --output text) ###aws ec2 detach-internet-gateway --internet-gateway-id $IGWID --vpc-id $VPCID ###aws ec2 delete-internet-gateway --internet-gateway-id $IGWID
3. Virtual Private Gateway作成
# 変数定義 export VPGWNAME=VPGW-MySystem # Virtual Private Gateway作成 export VPGWID=$(aws ec2 create-vpn-gateway --type ipsec.1 | awk '/VpnGatewayId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $VPGWID --tags Key=Name,Value=$VPGWNAME # VPCに割り当て aws ec2 attach-vpn-gateway --vpn-gateway-id $VPGWID --vpc-id $VPCID # describeで確認 aws ec2 describe-vpn-gateways --filters "Name=vpn-gateway-id,Values=$VPGWID" # 削除手順 ###export VPGWID=$(aws ec2 describe-vpn-gateways --query VpnGateways[].VpnGatewayId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$VPGWNAME" --output text) ###aws ec2 detach-vpn-gateway --vpn-gateway-id $VPGWID --vpc-id $VPCID ###aws ec2 delete-vpn-gateway --vpn-gateway-id $VPGWID
4. DHCPオプションにNameタグだけ設定(VPCデフォルトのまま利用)
# 変数定義 export DHCPOPSNAME=DHCP-MySystem export DHCPOPSID=$(aws ec2 describe-vpcs --vpc-ids $VPCID --query Vpcs[].DhcpOptionsId[] --output text) # Nameタグだけ設定 aws ec2 create-tags --resources $DHCPOPSID --tags Key=Name,Value=$DHCPOPSNAME # describeで確認 aws ec2 describe-dhcp-options --dhcp-options-ids $DHCPOPSID
5. Subnet作成
# 変数定義 export SUB1CIDR=10.100.0.0/24 export SUB1AZ=ap-northeast-1a export SUB1NAME=SN-MySystem-Public-1 # Subnet作成 export SUB1ID=$(aws ec2 create-subnet --vpc-id $VPCID --cidr-block $SUB1CIDR --availability-zone $SUB1AZ | awk '/SubnetId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $SUB1ID --tags Key=Name,Value=$SUB1NAME # PublicなのでAuto Assign Public IPする aws ec2 modify-subnet-attribute --subnet-id $SUB1ID --map-public-ip-on-launch # describeで確認 aws ec2 describe-subnets --subnet-ids $SUB1ID # 削除手順 ###export SUB1ID=$(aws ec2 describe-subnets --query Subnets[].SubnetId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$SUB1NAME" --output text) ###aws ec2 delete-subnet --subnet-id $SUB1ID
# 変数定義 export SUB2CIDR=10.100.1.0/24 export SUB2AZ=ap-northeast-1a export SUB2NAME=SN-MySystem-Private-1 # Subnet作成 export SUB2ID=$(aws ec2 create-subnet --vpc-id $VPCID --cidr-block $SUB2CIDR --availability-zone $SUB2AZ | awk '/SubnetId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $SUB2ID --tags Key=Name,Value=$SUB2NAME # PrivateなのでAuto Assign Public IPしない aws ec2 modify-subnet-attribute --subnet-id $SUB2ID --no-map-public-ip-on-launch # describeで確認 aws ec2 describe-subnets --subnet-ids $SUB2ID # 削除手順 ###export SUB2ID=$(aws ec2 describe-subnets --query Subnets[].SubnetId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$SUB2NAME" --output text) ###aws ec2 delete-subnet --subnet-id $SUB2ID
# 変数定義 export SUB3CIDR=10.100.2.0/24 export SUB3AZ=ap-northeast-1c export SUB3NAME=SN-MySystem-Public-2 # Subnet作成 export SUB3ID=$(aws ec2 create-subnet --vpc-id $VPCID --cidr-block $SUB3CIDR --availability-zone $SUB3AZ | awk '/SubnetId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $SUB3ID --tags Key=Name,Value=$SUB3NAME # PublicなのでAuto Assign Public IPする aws ec2 modify-subnet-attribute --subnet-id $SUB3ID --map-public-ip-on-launch # describeで確認 aws ec2 describe-subnets --subnet-ids $SUB3ID # 削除手順 ###export SUB3ID=$(aws ec2 describe-subnets --query Subnets[].SubnetId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$SUB3NAME" --output text) ###aws ec2 delete-subnet --subnet-id $SUB3ID
# 変数定義 export SUB4CIDR=10.100.3.0/24 export SUB4AZ=ap-northeast-1c export SUB4NAME=SN-MySystem-Private-2 # Subnet作成 export SUB4ID=$(aws ec2 create-subnet --vpc-id $VPCID --cidr-block $SUB4CIDR --availability-zone $SUB4AZ | awk '/SubnetId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $SUB4ID --tags Key=Name,Value=$SUB4NAME # PrivateなのでAuto Assign Public IPしない aws ec2 modify-subnet-attribute --subnet-id $SUB4ID --no-map-public-ip-on-launch # describeで確認 aws ec2 describe-subnets --subnet-ids $SUB4ID # 削除手順 ###export SUB4ID=$(aws ec2 describe-subnets --query Subnets[].SubnetId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$SUB4NAME" --output text) ###aws ec2 delete-subnet --subnet-id $SUB4ID
6. Route Table作成
NATインスタンスがまだ無いので、PrivateサブネットはVPGWへのルートのみ追加する手順とした。あと、Public用のRoute Tableは共通だけど、NATインスタンスはAZごとに追加する想定なので、それぞれ別のRoute Tableとした。
# 変数定義 # サブネットはNameタグで拾ってくる export RT1NAME=RT-MySystem-Public export PUBSUBLIST=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" "Name=tag-key,Values=Name" "Name=tag-value,Values=*Public*" --query 'Subnets[].SubnetId[]' --output text) # Route Table作成 export RT1ID=$(aws ec2 create-route-table --vpc-id $VPCID | awk '/RouteTableId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $RT1ID --tags Key=Name,Value=$RT1NAME # ルート追加 # Nameタグから拾ってきたサブネットに割り当て aws ec2 create-route --route-table-id $RT1ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGWID for PUBSUB in $PUBSUBLIST do aws ec2 associate-route-table --route-table-id $RT1ID --subnet-id $PUBSUB done # describeで確認 aws ec2 describe-route-tables --route-table-ids $RT1ID # 削除手順 ###export RT1ID=$(aws ec2 describe-route-tables --query RouteTables[].RouteTableId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$RT1NAME" --output text) ###ASSOCIDS=$(aws ec2 describe-route-tables --filters "Name=vpc-id,Values=$VPCID" "Name=route-table-id,Values=$RT1ID" --query 'RouteTables[].Associations[].RouteTableAssociationId[]' --output text) ###for ASSOCID in $ASSOCIDS ###do ### aws ec2 disassociate-route-table --association-id $ASSOCID ###done ###aws ec2 delete-route-table --route-table-id $RT1ID
# 変数定義 # サブネットはNameタグで拾ってくる export RT2NAME=RT-MySystem-Private1 export PRIVSUBLIST1=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" "Name=tag-key,Values=Name" "Name=tag-value,Values=*Private-1*" --query 'Subnets[].SubnetId[]' --output text) # Route Table作成 export RT2ID=$(aws ec2 create-route-table --vpc-id $VPCID | awk '/RouteTableId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # Nameタグ設定 aws ec2 create-tags --resources $RT2ID --tags Key=Name,Value=$RT2NAME # ルート追加(NATインスタンスを追加した後にさらにルート追加される想定) # Nameタグから拾ってきたサブネットに割り当て aws ec2 create-route --route-table-id $RT2ID --destination-cidr-block 10.0.0.0/8 --gateway-id $VPGWID for PRIVSUB1 in $PRIVSUBLIST1 do aws ec2 associate-route-table --route-table-id $RT2ID --subnet-id $PRIVSUB1 done # describeで確認 aws ec2 describe-route-tables --route-table-ids $RT2ID # 削除手順 ###export RT2ID=$(aws ec2 describe-route-tables --query RouteTables[].RouteTableId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$RT2NAME" --output text) ###ASSOCIDS=$(aws ec2 describe-route-tables --filters "Name=vpc-id,Values=$VPCID" "Name=route-table-id,Values=$RT2ID" --query 'RouteTables[].Associations[].RouteTableAssociationId[]' --output text) ###for ASSOCID in $ASSOCIDS ###do ### aws ec2 disassociate-route-table --association-id $ASSOCID ###done ###aws ec2 delete-route-table --route-table-id $RT2ID
# 変数定義 # サブネットはNameタグで拾ってくる export RT3NAME=RT-MySystem-Private2 export PRIVSUBLIST2=$(aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" "Name=tag-key,Values=Name" "Name=tag-value,Values=*Private-2*" --query 'Subnets[].SubnetId[]' --output text) # Route Table作成 export RT3ID=$(aws ec2 create-route-table --vpc-id $VPCID | awk '/RouteTableId/ {gsub(/\"/, "");gsub(/,/,""); print $2}') # ルート追加(NATインスタンスを追加した後にさらにルート追加される想定) # Nameタグから拾ってきたサブネットに割り当て aws ec2 create-tags --resources $RT3ID --tags Key=Name,Value=$RT3NAME aws ec2 create-route --route-table-id $RT3ID --destination-cidr-block 10.0.0.0/8 --gateway-id $VPGWID for PRIVSUB2 in $PRIVSUBLIST2 do aws ec2 associate-route-table --route-table-id $RT3ID --subnet-id $PRIVSUB2 done # describeで確認 aws ec2 describe-route-tables --route-table-ids $RT3ID # 削除手順 ###export RT3ID=$(aws ec2 describe-route-tables --query RouteTables[].RouteTableId[] --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=$RT3NAME" --output text) ###ASSOCIDS=$(aws ec2 describe-route-tables --filters "Name=vpc-id,Values=$VPCID" "Name=route-table-id,Values=$RT3ID" --query 'RouteTables[].Associations[].RouteTableAssociationId[]' --output text) ###for ASSOCID in $ASSOCIDS ###do ### aws ec2 disassociate-route-table --association-id $ASSOCID ###done ###aws ec2 delete-route-table --route-table-id $RT3ID
ここまで作るならCloudFormationかもと思ったけど、変更管理しないものをCloudFormationで作成するのは適切ではないとの判断で、AWS CLIでの手順としてみた(本当はCloudFormationがまだ使いこなせるほどわかっていないという噂も)。これ以外にも構築手順は全てCLIで作成中。これにNATも追加すれば良いけど、可用性の要件が環境により異なると思うので。
需要があるかわからないけど、参考にしてくれる人が一人でもいたらとても嬉しい。