はじめに
ここでは踏み台サーバー用のVPCを作成してみます。
以下のように、他の VPC に接続するために踏み台サーバーを配置するために使用します。
VPC Peering や Transit Gateway を使用して他の VPCに接続する事を想定しています。(VPC Peering や Transit Gateway接続の手順はここでは扱いません)
VPC の作成
VPC の Network、その中に作り混む Public Subnet そして Private Subnet のレンジを、最低限決める必要があります。
ここでは以下のように決めました。
VPC の Network 10.8.0.0/16
VPC 内の Public Subnet 10.8.128.0/17
VPC 内の Private Subnet 10.8.0.0/17
この後は、コマンドラインで作成して行きます。
一つ一つコマンドを打つのは大変なのでシェル化しています。
(※ここでは Single Zone 用にネットワークを構成しています。Multi AZ にするには、サブネット等の必要なコンポーネントを AZ分作成する必要があります)
#!/bin/bash
VPC_NETWORK=10.8.0.0/16 # VPC の Network
VPC_SUBNET_PUBLIC=10.8.128.0/17 # VPC 内の Public Subnet
VPC_SUBNET_PRIVATE=10.8.0.0/17 # VPC 内の Private Subnet
# Create a VPC
echo "[STEP1] Create VPC " $VPC_NETWORK
VPC_ID=`aws ec2 create-vpc --cidr-block $VPC_NETWORK | jq -r .Vpc.VpcId`
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames | jq .
echo "VPCID = " $VPC_ID "has been created"
# Create a public subnet in the VPC
echo "[STEP2] Create Public Subnet " $VPC_SUBNET_PUBLIC
PUBLIC_SUBNET=`aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $VPC_SUBNET_PUBLIC | jq -r .Subnet.SubnetId`
aws ec2 create-tags --resources $PUBLIC_SUBNET --tags Key=Name,Value=my-public | jq .
echo "Public subnet ID = " $PUBLIC_SUBNET "has been created"
# Create a privatesubnet in the VPC
echo "[STEP3] Create Private Subnet " $VPC_SUBNET_PRIVATE
PRIVATE_SUBNET=`aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $VPC_SUBNET_PRIVATE | jq -r .Subnet.SubnetId`
aws ec2 create-tags --resources $PRIVATE_SUBNET --tags Key=Name,Value=my-private | jq .
echo "Private subnet ID = " $PRIVATE_SUBNET "has been created"
# Create Internet Gateway
echo "[STEP4] Create Internet Gateway in VPC " $VPC_ID
I_GW=`aws ec2 create-internet-gateway | jq -r .InternetGateway.InternetGatewayId`
aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $I_GW | jq .
echo "Internet Gateway ID = " $I_GW "has been created"
# Create a route table for public subnet
echo "[STEP5] Create a Route table for the public subnet id" $PUBLIC_SUBNET
R_TABLE=`aws ec2 create-route-table --vpc-id $VPC_ID | jq -r .RouteTable.RouteTableId`
# -- sometimes it takes time to get Route Table id --
while ! aws ec2 describe-route-tables --route-table-id $R_TABLE | jq .; do sleep 1; done
aws ec2 create-route --route-table-id $R_TABLE --destination-cidr-block 0.0.0.0/0 --gateway-id $I_GW | jq .
aws ec2 associate-route-table --subnet-id $PUBLIC_SUBNET --route-table-id $R_TABLE | jq .
echo "Route table ID " $R_TABLE " for the public subnet(" $PUBLIC_SUBNET ") has been created"
# Create a NAT Gateway
echo "[STEP6] Create NAT Gateway in " $PUBLIC_SUBNET
EIP=`aws ec2 allocate-address --domain vpc | jq -r .AllocationId`
NAT_GW=`aws ec2 create-nat-gateway --subnet-id $PUBLIC_SUBNET --allocation-id $EIP | jq -r .NatGateway.NatGatewayId`
echo "NAT Gateway ID " $NAT_GW " has been created in the public subnet(" $PUBLIC_SUBNET ")"
# Wait for NAT Gateway created. Sometimes it took a few minutes
NAT_GW_STATUS=`aws ec2 describe-nat-gateways --nat-gateway-id $NAT_GW | jq -r .NatGateways[].State`
echo "- NAT Gateway status is " $NAT_GW_STATUS
while [ $NAT_GW_STATUS != "available" ]
do
NAT_GW_STATUS=`aws ec2 describe-nat-gateways --nat-gateway-id $NAT_GW | jq -r .NatGateways[].State`
if [ $NAT_GW_STATUS != "available" ] ; then
echo "- NAT Gatewya id = " $NAT_GW " State = " $NAT_GW_STATUS
echo "- Waiting for the NAT Gateway available"
sleep 10;
else
echo "- NAT Gatewya id = " $NAT_GW " State = " $NAT_GW_STATUS
fi
done
# Create a Route Tatble for Private subnet
echo "[STEP7] Create a Route Table for the private subnet " $PRIVATE_SUBNET
R_TABLE_NAT=`aws ec2 create-route-table --vpc-id $VPC_ID | jq -r .RouteTable.RouteTableId`
# -- sometimes it takes time to get Route Table id --
while ! aws ec2 describe-route-tables --route-table-id $R_TABLE_NAT | jq . ; do sleep 1; done
aws ec2 create-route --route-table-id $R_TABLE_NAT --destination-cidr-block 0.0.0.0/0 --gateway-id $NAT_GW | jq .
aws ec2 associate-route-table --subnet-id $PRIVATE_SUBNET --route-table-id $R_TABLE_NAT | jq .
echo "Route table ID " $R_TABLE_NAT " for the public subnet(" $PRIVATE_SUBNET ") has been created"
EC2インスタンスの作成
直接 Private Subnet には入れないので、Public Subnet と Private Subnet にそれぞれ EC2 を配置する必要があります。
この手順は簡単なので後ほど。
VPC ID の取得
$ aws ec2 describe-vpcs | jq -r '.Vpcs[] | [.CidrBlock, .VpcId] | @csv'
"10.7.0.0/16","vpc-0e403f03014e706c3"
"10.8.0.0/16","vpc-08e6b9ecd4e90c949" # Bastion 用に 今回作成したのはこれ
$
セキュリティグループの作成
$ export VPC_ID=vpc-08e6b9ecd4e90c949
$ aws ec2 create-security-group --group-name "bastion-scg" --description "bastion" --vpc-id $VPC_ID
{
"GroupId": "sg-01edf951b3eee98e4"
}
$
# 返ってきた GroupId を変数に入力
$ export SG_ID=sg-01edf951b3eee98e4
# SSH 用に Port 22 を開ける設定をする
$ aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 22 --cidr 0.0.0.0/0
EC2のキーペアの作成
$ aws ec2 create-key-pair --key-name BastionKeyPair --query "KeyMaterial" --output text > BastionKeyPair.pem
$ chmod 400 BastionKeyPair.pem # 鍵のパーミッションが緩いと ssh ができないので、適切なパーミッションに変更
Public Subnet 内へのEC2インスタンスの作成
Public Subnet 内の EC2 インスタンスには、Elastic IPを与える必要があります。
EC2を作る Subnet ID が必要なので Subnet ID を調べます。
$ aws ec2 describe-subnets | jq -r '.Subnets[] | [ .CidrBlock, .SubnetId, .AvailabilityZone, .Tags[].Value ] | @csv'
"10.8.128.0/17","subnet-0d1224192eb265726","ap-northeast-1c","my-public" # 最初は、ここに EC2を作る
"10.7.128.0/17","subnet-0a2360ce9dca34f9d","ap-northeast-1d","shared","my-public"
"10.7.0.0/17","subnet-03a000478bacb81f6","ap-northeast-1d","my-private","shared"
"10.8.0.0/17","subnet-0a4ecb7a715715c60","ap-northeast-1c","my-private" # 次は、ここに EC2を作る
$
$ export PUB_SUBNET_ID=subnet-0d1224192eb265726 # Public Subnet の ID
$ export SG_ID=sg-01edf951b3eee98e4 # 作成した Security Group の ID
$ export KEY_PAIR_NAME=BastionKeyPair # 作成した Key Pair の名前
$ aws ec2 run-instances \
--image-id ami-00f045aed21a55240 \
--count 1 \
--instance-type t2.micro \
--key-name $KEY_PAIR_NAME \
--security-group-ids $SG_ID \
--subnet-id $PUB_SUBNET_ID \
--associate-public-ip-address
$
Private Subnet 内へのEC2インスタンスの作成
$ export PRIVATE_SUBNET_ID=subnet-0a4ecb7a715715c60 # Private Subnet の ID
$ export SG_ID=sg-01edf951b3eee98e4 # 変更無し
$ export KEY_PAIR_NAME=BastionKeyPair # 変更無し
$ aws ec2 run-instances \
--image-id ami-00f045aed21a55240 \
--count 1 \
--instance-type t2.micro \
--key-name $KEY_PAIR_NAME \
--security-group-ids $SG_ID \
--subnet-id $PRIVATE_SUBNET_ID \
--no-associate-public-ip-address
$
EC2インスタンスへのアクセス確認
作成した EC2 の IPアドレスを確認します。
$ aws ec2 describe-instances | jq -r '.Reservations[] | [.Instances[].InstanceType, .Instances[].InstanceId, .Instances[].State.Name, .Instances[].PrivateIpAddress, .Instances[].PublicIpAddress ] | @csv'
"t2.micro","i-007604a2516790360","running","10.8.129.192","13.231.221.123"
"t2.micro","i-0d513d50bc6e871a1","running","10.8.63.146",
$
Public Subnet に作った EC2は、インターネット向けのIPと Private IP の2つを持っている事に注目しましょう。
Public SubnetにあるEC2インスタンスにログイン
変数に Pubilc Bastion のIPアドレスをセットします。
$export PUBLIC_BASTION=13.231.221.123 # PUBLIC 側は Global IPを使う
Public Subnet にある EC2にログインします。
$ ssh -i BastionKeyPair.pem ec2-user@$PUBLIC_BASTION
The authenticity of host '13.231.221.123 (13.231.221.123)' can't be established.
ECDSA key fingerprint is SHA256:NgzW7WXI+DUccMWliMonHxmOkc2J7PFhturC3edMNfE.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '13.231.221.123' (ECDSA) to the list of known hosts.
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
47 package(s) needed for security, out of 94 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-10-8-129-192 ~]$ exit # 一旦抜ける
ログインした EC2からは一旦ログアウトしておきます。
Private SubnetにあるEC2インスタンスにログイン
ローカルに作成してある KeyPair を Public Subnet にあるEC2に scp
でコピーします。
$ scp -i BastionKeyPair.pem ./BastionKeyPair.pem ec2-user@$PUBLIC_BASTION:/home/ec2-user
Public Subnet にあるEC2に ssh
ログインして鍵の権限を 400 に変更します。
$ ssh -i BastionKeyPair.pem ec2-user@$PUBLIC_BASTION
$ chmod 400 BastionKeyPair.pem
変数に Private Bastion サーバーのIPをセットします。
$ export PRIVATE_BASTION=10.8.63.146
現在ログインしている EC2から、さらに Private Subnet にあるEC2にログインします。
[ec2-user@ip-10-8-129-192 ~]$ ssh -i BastionKeyPair.pem ec2-user@$PRIVATE_BASTION
The authenticity of host '10.8.63.146 (10.8.63.146)' can't be established.
ECDSA key fingerprint is SHA256:dwR3Blv3z3aJNcG3JdbRb1eiiZ5IFh6oN40143anS5c.
ECDSA key fingerprint is MD5:7d:b7:b6:e5:23:8a:8a:58:59:4d:cf:2f:a4:c7:40:42.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.8.63.146' (ECDSA) to the list of known hosts.
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-2/
47 package(s) needed for security, out of 94 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-10-8-63-146 ~]$
ログインできる事が確認できれば、完了です。
EC2 の CLI での起動/停止
コスト節約のために踏み台の EC2を止める場合、以下のようにします。
インスタンスIDのリストの取得
$ aws ec2 describe-instances | jq -r '.Reservations[] | [.Instances[].InstanceType, .Instances[].InstanceId, .Instances[].State.Name, .Instances[].PrivateIpAddress, .Instances[].PublicIpAddress ] | @csv'
"t2.micro","i-0a6d6f2ceeacfd599","running","10.8.132.237","54.238.201.65"
"t2.micro","i-03549090839a17cab","running","10.8.19.122",
$
インスタンスの停止
$ aws ec2 stop-instances --instance-ids i-03549090839a17cab i-0a6d6f2ceeacfd599
インスタンスの開始
aws ec2 start-instances --instance-ids i-03549090839a17cab i-0a6d6f2ceeacfd599