AWSのVPCをShellスクリプトで作る
まぁありきたりなんですが、必要に駆られてVPCとサブネットとルートテーブルおよびNATGatewayを作成するShellスクリプト準備しました。既にいろんな人がやってますが、まぁ備忘録的に置いておきます。
◆シリーズ
VPCとサブネットの作成
◆Shellスクリプト本体
#!/bin/bash
# スクリプト実行時にファイル名を指定
if [ -z "$1" ]; then
echo "Usage: $0 <rules-file>" >&2
exit 1
fi
RESOURCE_FILE=$1
# リソースファイルが存在するか確認
if [ ! -f "$RESOURCE_FILE" ]; then
echo "エラー: ファイル $RESOURCE_FILE が見つかりません。"
exit 1
fi
# リソースファイルを読み込み、ヘッダーをスキップ
RESOURCES=()
while IFS= read -r line; do
if [[ ! "$line" =~ ^REGION ]]; then
RESOURCES+=("$line")
fi
done < "$RESOURCE_FILE"
# リージョンごとの処理
#CURRENT_REGION=""
#declare -A PROCESSED_VPCS
#declare -A ROUTE_TABLES
#declare -A NAT_GATEWAYS
#declare -A FIRST_PUBLIC_SUBNETS
for RESOURCE in "${RESOURCES[@]}"; do
IFS=',' read -r REGION VPC_NAME VPC_CIDR SUBNET_CIDR AZ TYPE NAME ROUTE_TABLE_NAME COST_TAG <<< "${RESOURCE}"
# リージョンが切り替わった場合、変数をリセット
if [ "$REGION" != "$CURRENT_REGION" ]; then
unset PROCESSED_VPCS
unset ROUTE_TABLES
unset NAT_GATEWAYS
unset FIRST_PUBLIC_SUBNETS
echo "リージョンが切り替わりました: ${REGION}"
CURRENT_REGION=$REGION
declare -A PROCESSED_VPCS
declare -A ROUTE_TABLES
declare -A NAT_GATEWAYS
declare -A FIRST_PUBLIC_SUBNETS
fi
# リージョンとVPCごとに処理を開始
if [ -z "${PROCESSED_VPCS[$VPC_NAME]}" ]; then
echo "リージョン ${REGION} の VPC ${VPC_NAME} の処理を開始します..."
# VPC作成または既存のVPC取得
EXISTING_VPC_ID=$(aws ec2 describe-vpcs \
--region $REGION \
--filters "Name=tag:Name,Values=${VPC_NAME}" \
--query 'Vpcs[0].VpcId' \
--output text)
if [ "$EXISTING_VPC_ID" != "None" ]; then
echo "既存のVPCを使用します: ${EXISTING_VPC_ID}"
EC2_VPC_ID=$EXISTING_VPC_ID
# 既存のIGWを取得
IGW_ID=$(aws ec2 describe-internet-gateways \
--region $REGION \
--filters "Name=attachment.vpc-id,Values=${EC2_VPC_ID}" \
--query 'InternetGateways[0].InternetGatewayId' \
--output text)
echo "既存のインターネットゲートウェイ ID: ${IGW_ID}"
else
echo "VPCを作成中..."
EC2_VPC_ID=$(aws ec2 create-vpc \
--region $REGION \
--cidr-block ${VPC_CIDR} \
--tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=${VPC_NAME}},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'Vpc.VpcId' \
--output text)
echo "VPC ID: ${EC2_VPC_ID}"
# インターネットゲートウェイ作成とアタッチ
echo "インターネットゲートウェイを作成中..."
IGW_ID=$(aws ec2 create-internet-gateway \
--region $REGION \
--tag-specifications "ResourceType=internet-gateway,Tags=[{Key=Name,Value=${VPC_NAME}-igw},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'InternetGateway.InternetGatewayId' \
--output text)
aws ec2 attach-internet-gateway --region $REGION --internet-gateway-id ${IGW_ID} --vpc-id ${EC2_VPC_ID}
echo "インターネットゲートウェイ ID: ${IGW_ID}"
fi
PROCESSED_VPCS[$VPC_NAME]=1
fi
# サブネット作成
echo "サブネット ${NAME} を作成中..."
SUBNET_ID=$(aws ec2 create-subnet \
--region $REGION \
--vpc-id ${EC2_VPC_ID} \
--cidr-block ${SUBNET_CIDR} \
--availability-zone ${AZ} \
--tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=${VPC_NAME}-${NAME}},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'Subnet.SubnetId' \
--output text 2>/dev/null || echo "")
if [ -z "$SUBNET_ID" ]; then
echo "サブネットの作成に失敗しました。CIDRブロックや設定を確認してください。"
continue
fi
echo "${TYPE} サブネット (${AZ}) ID: ${SUBNET_ID}"
# パブリックサブネットの場合、パブリックIP自動割り当てを有効化
if [[ "${TYPE}" == public ]]; then
aws ec2 modify-subnet-attribute --region $REGION --subnet-id ${SUBNET_ID} --map-public-ip-on-launch
if [ -z "${FIRST_PUBLIC_SUBNETS[$VPC_NAME]}" ]; then
FIRST_PUBLIC_SUBNETS[$VPC_NAME]=${SUBNET_ID}
fi
fi
# ルートテーブル作成または取得(必要に応じて)
if [ -z "${ROUTE_TABLES[$VPC_NAME,$ROUTE_TABLE_NAME]}" ]; then
EXISTING_RT_ID=$(aws ec2 describe-route-tables \
--region $REGION \
--filters "Name=vpc-id,Values=${EC2_VPC_ID}" "Name=tag:Name,Values=${VPC_NAME}-${ROUTE_TABLE_NAME}" \
--query 'RouteTables[0].RouteTableId' \
--output text)
if [ "$EXISTING_RT_ID" != "None" ]; then
echo "既存のルートテーブルを使用します: ${EXISTING_RT_ID}"
ROUTE_TABLES[$VPC_NAME,$ROUTE_TABLE_NAME]=$EXISTING_RT_ID
else
echo "ルートテーブル ${ROUTE_TABLE_NAME} を作成中..."
RT_ID=$(aws ec2 create-route-table \
--region $REGION \
--vpc-id ${EC2_VPC_ID} \
--tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=${VPC_NAME}-${ROUTE_TABLE_NAME}},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'RouteTable.RouteTableId' \
--output text)
ROUTE_TABLES[$VPC_NAME,$ROUTE_TABLE_NAME]=$RT_ID
echo "ルートテーブル ID: ${RT_ID}"
# パブリックルートの場合、インターネットゲートウェイを設定
if [[ "${TYPE}" == public ]]; then
aws ec2 create-route \
--region $REGION \
--route-table-id $RT_ID \
--destination-cidr-block '0.0.0.0/0' \
--gateway-id $IGW_ID
fi
fi
fi
# サブネットとルートテーブルの関連付け
aws ec2 associate-route-table \
--region $REGION \
--subnet-id $SUBNET_ID \
--route-table-id ${ROUTE_TABLES[$VPC_NAME,$ROUTE_TABLE_NAME]}
# NATゲートウェイが必要な場合(`private-nat` タイプ)
if [[ "${TYPE}" == private-nat ]]; then
NAT_GATEWAY_KEY="${VPC_NAME},${AZ}-natgw"
if [ -z "${NAT_GATEWAYS[$NAT_GATEWAY_KEY]}" ]; then
EXISTING_NAT_GATEWAY=$(aws ec2 describe-nat-gateways \
--region $REGION \
--filter "Name=vpc-id,Values=${EC2_VPC_ID}" "Name=subnet-id,Values=${FIRST_PUBLIC_SUBNETS[$VPC_NAME]}" \
"Name=state,Values=available" \
--query 'NatGateways[?Tags[?Key==`Name` && Value==`'"${VPC_NAME}-${AZ}-natgw"'`]].NatGatewayId' \
--output text)
if [ -n "$EXISTING_NAT_GATEWAY" ] && [ "$EXISTING_NAT_GATEWAY" != "None" ]; then
echo "既存のNATゲートウェイを使用します (${AZ}): $EXISTING_NAT_GATEWAY"
NAT_GATEWAYS[$NAT_GATEWAY_KEY]=$EXISTING_NAT_GATEWAY
else
echo "NATゲートウェイを作成中 (${AZ})..."
EIP_ALLOC_ID=$(aws ec2 allocate-address \
--region $REGION \
--tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=${VPC_NAME}-${AZ}-natgw-ip},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'AllocationId' \
--output text)
NAT_GATEWAY_ID=$(aws ec2 create-nat-gateway \
--region $REGION \
--subnet-id ${FIRST_PUBLIC_SUBNETS[$VPC_NAME]} \
--allocation-id $EIP_ALLOC_ID \
--tag-specifications "ResourceType=natgateway,Tags=[{Key=Name,Value=${VPC_NAME}-${AZ}-natgw},{Key=Costdiv,Value=${COST_TAG}}]" \
--query 'NatGateway.NatGatewayId' \
--output text)
NAT_GATEWAYS[$NAT_GATEWAY_KEY]=$NAT_GATEWAY_ID
# NATゲートウェイが利用可能になるまで待機
echo "NATゲートウェイ (${AZ}) の準備を待機中..."
aws ec2 wait nat-gateway-available --region $REGION --nat-gateway-ids $NAT_GATEWAY_ID
# プライベートルートテーブルにNATゲートウェイルートを追加
aws ec2 create-route \
--region $REGION \
--route-table-id ${ROUTE_TABLES[$VPC_NAME,$ROUTE_TABLE_NAME]} \
--destination-cidr-block '0.0.0.0/0' \
--nat-gateway-id $NAT_GATEWAY_ID
echo "NATゲートウェイルートを追加しました (${AZ})"
fi
fi
fi
done
echo "全てのリージョンとVPCの処理が完了しました!"
読み込むファイルは以下の様な感じで作成します。(CSVで時代遅れな感じですが・・・)
cat <<_EOF_ > vpcsubnets.csv REGION,VPC_NAME,VPC_CIDR,SUBNET_CIDR,AZ,TYPE,NAME,ROUTE_TABLE_NAME,COST_TAG ap-northeast-1,test1-vpc,192.168.0.0/16,192.168.1.0/24,ap-northeast-1a,public,public-subnet-a1,public-rt,handson ap-northeast-1,test1-vpc,192.168.0.0/16,192.168.2.0/24,ap-northeast-1c,public,public-subnet-c1,public-rt,handson ap-northeast-1,test1-vpc,192.168.0.0/16,192.168.11.0/24,ap-northeast-1a,private-nat,private-subnet-a1,private-rt-a,handson ap-northeast-1,test1-vpc,192.168.0.0/16,192.168.12.0/24,ap-northeast-1c,private-no-nat,private-subnet-c1,private-rt-a,handson _EOF_
セキュリティグループとかもほしいと言えばほしいですけど
とりあえずVPCとルートテーブルとサブネットだけ何とかってケースでは重宝かも
コメント