AWSのセキュリティグループをShellスクリプトで作る
前回はVPCとサブネットを作成したんで、今回はセキュリティグループを作成してみた。これは使用シーン多いので結構、重宝するかもしれない。ありきたりだけどなかなかほしいと思うのがなかったので作成。例のごとくレガシーなCSVファイル読込という古い形式です。
◆シリーズ
セキュリティグループの作成
◆Shellスクリプト本体
#!/bin/bash # 変数の設定 RULES_FILE=$1 # ルールを記述したCSVファイル # 引数の検証 if [ $# -ne 1 ]; then echo "Usage: $0 <rule_file.csv>" >&2 exit 1 fi # ファイルの存在確認 if [[ ! -f "$RULES_FILE" ]]; then echo "ルールファイルが見つかりません: $RULES_FILE" >&2 exit 1 fi # VPC名とリージョンからVPC IDを取得する関数 get_vpc_id() { local REGION=$1 local VPC_NAME=$2 local VPC_ID=$(aws ec2 describe-vpcs \ --region ${REGION} \ --filters "Name=tag:Name,Values=${VPC_NAME}" \ --query "Vpcs[0].VpcId" \ --output text ) if [[ $VPC_ID == "None" ]]; then echo "エラー: VPC名 '${VPC_NAME}' はリージョン '${REGION}' に存在しません。" >&2 exit 1 fi echo $VPC_ID } # プレフィックスリスト名からIDを取得する関数 get_prefix_list_id() { local REGION=$1 local PREFIX_LIST_NAME=$2 local PREFIX_LIST_ID=$(aws ec2 describe-managed-prefix-lists \ --region ${REGION} \ --filters "Name=prefix-list-name,Values=${PREFIX_LIST_NAME}" \ --query "PrefixLists[0].PrefixListId" \ --output text ) if [[ $PREFIX_LIST_ID == "None" ]]; then echo "" else echo $PREFIX_LIST_ID fi } # セキュリティグループ名からIDを取得する関数 get_security_group_id() { local REGION=$1 local SG_NAME=$2 local SG_ID=$(aws ec2 describe-security-groups \ --region ${REGION} \ --filters "Name=group-name,Values=${SG_NAME}" \ --query "SecurityGroups[0].GroupId" \ --output text) if [[ $SG_ID == "None" ]]; then echo "" else echo $SG_ID fi } # セキュリティグループに同一ルールが既に存在するか確認する関数 rule_exists() { local REGION=$1 local GROUP_ID=$2 local PROTOCOL=$3 local FROM_PORT=$4 local TO_PORT=$5 local TARGET=$6 # 既存のルールを取得 EXISTING_RULES=$(aws ec2 describe-security-group-rules \ --region ${REGION} \ --filters "Name=group-id,Values=${GROUP_ID}" \ --query "SecurityGroupRules[?IpProtocol=='${PROTOCOL}' && FromPort==\`${FROM_PORT}\` && ToPort==\`${TO_PORT}\`]" \ --output json ) # ターゲットがCIDRの場合 if [[ ${TARGET} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then echo "${EXISTING_RULES}" | jq -e --arg TARGET "${TARGET}" '.[] | select(.CidrIpv4 == $TARGET)' > /dev/null return $? # ターゲットがセキュリティグループIDの場合 elif [[ ${TARGET} =~ ^sg- ]]; then echo "${EXISTING_RULES}" | jq -e --arg TARGET "${TARGET}" '.[] | select(.ReferencedGroupInfo.GroupId == $TARGET)' > /dev/null return $? # ターゲットがプレフィックスリストIDの場合 elif [[ ${TARGET} =~ ^pl- ]]; then echo "${EXISTING_RULES}" | jq -e --arg TARGET "${TARGET}" '.[] | select(.PrefixListId == $TARGET)' > /dev/null return $? fi return 1 } # 作業対象のセキュリティグループの名前とIDをマッピング # 存在しない場合は新規で作成 # 対象は引数にしたファイル内のリージョン、VPC ID、名前、説明が一意のものを抽出 declare -A sg_map while IFS=, read -r REGION VPC_NAME NAME DESCRIPTION do VPCID=$(get_vpc_id ${REGION} ${VPC_NAME}) if [ -z ${sg_map[${REGION}${VPCID}${NAME}]} ]; then sg_id=$(aws ec2 describe-security-groups \ --region ${REGION} \ --filters "Name=vpc-id,Values=${VPCID}" "Name=group-name,Values=${NAME}" \ --query "SecurityGroups[0].GroupId" \ --output text ) if [[ $sg_id == "None" ]]; then echo "新しいセキュリティグループを作成します: ${NAME} (${REGION})" sg_map[${REGION}${VPCID}${NAME}]=$(aws ec2 create-security-group \ --region ${REGION} \ --group-name ${NAME} \ --description "${DESCRIPTION}" \ --vpc-id ${VPCID} \ --query 'GroupId' \ --output text ) else echo "セキュリティグループが既に存在します: ${NAME} (${REGION})" sg_map[${REGION}${VPCID}${NAME}]=$sg_id fi fi done << EOS $(awk 'BEGIN{FS=","; OFS=","} NR>1 {print $1,$2,$3,$4}' ${RULES_FILE} | sort | uniq) EOS # 引数にしたファイルを読み込みセキュリティグループのルールを修正 # ファイルの1行目はヘッダーとして無視する while IFS=, read -r REGION VPC_NAME NAME DESCRIPTION ACTION DIRECTION PROTOCOL FROM_PORT TO_PORT TARGET RULE_DESCRIPTION do VPCID=$(get_vpc_id ${REGION} ${VPC_NAME}) if [ "${ACTION}" == "add" ]; then ACT="authorize" if [ -z "$RULE_DESCRIPTION" ]; then RLDESC="" else RLDESC=",Description=${RULE_DESCRIPTION}" fi elif [ "${ACTION}" == "remove" ]; then ACT="revoke" RLDESC="" fi SCMD="${ACT}-security-group-${DIRECTION}" # ターゲットの種類を判定 if [[ ${TARGET} =~ ^sg- ]]; then TARGET_TYPE="GroupId" elif [[ ${TARGET} =~ ^pl- ]]; then TARGET_TYPE="PrefixListId" else # セキュリティグループ名の場合 SG_ID=$(get_security_group_id ${REGION} ${TARGET}) if [[ -n $SG_ID ]]; then TARGET=$SG_ID TARGET_TYPE="GroupId" else # プレフィックスリスト名の場合 PL_ID=$(get_prefix_list_id ${REGION} ${TARGET}) if [[ -n $PL_ID ]]; then TARGET=$PL_ID TARGET_TYPE="PrefixListId" else # CIDRブロックの場合 TARGET_TYPE="CidrIp" fi fi fi if [[ $TARGET_TYPE == "GroupId" ]]; then RULE_TARGET="UserIdGroupPairs=[{GroupId=${TARGET}${RLDESC}}]" elif [[ $TARGET_TYPE == "PrefixListId" ]]; then RULE_TARGET="PrefixListIds=[{PrefixListId=${TARGET}${RLDESC}}]" else RULE_TARGET="IpRanges=[{CidrIp=${TARGET}${RLDESC}}]" fi PACKET="IpProtocol=${PROTOCOL}" if [ "${PROTOCOL}" != "-1" ]; then PACKET="${PACKET},FromPort=${FROM_PORT},ToPort=${TO_PORT}" fi PERMISSIONS="${PACKET},${RULE_TARGET}" # addの場合、同一ルールが既に存在するか確認 if [ "${ACTION}" == "add" ]; then if rule_exists ${REGION} ${sg_map[${REGION}${VPCID}${NAME}]} ${PROTOCOL} ${FROM_PORT} ${TO_PORT} ${TARGET}; then echo "同一ルールが既に存在します: ${DIRECTION}-${PROTOCOL}-${FROM_PORT}-${TO_PORT}-${TARGET}" continue fi fi echo "${ACTION} ルール: セキュリティグループ ${NAME}: ${DIRECTION}-${PROTOCOL}-${FROM_PORT}-${TO_PORT}-${TARGET}" aws ec2 ${SCMD} --region ${REGION} --group-id ${sg_map[${REGION}${VPCID}${NAME}]} --ip-permissions "${PERMISSIONS}" 1> /dev/null if [ $? -eq 0 ]; then echo "${ACTION} ルールの適用に成功しました" else echo "${ACTION} ルールの適用に失敗しました" fi done << EOS $(awk 'BEGIN{FS=","; OFS=","} NR>1 {print $0}' ${RULES_FILE}) EOS
で、例のごとく読込用のCSVファイルのサンプル、addのところremoveとすると既存のセキュリティグループからルールを削除できる。
cat <<_EOF_ > securitygroups.csv region,VPC_name,group_name,description,action,direction,protocol,from_port,to_port,source,rule_description ap-northeast-1,handson-cli-vpc,my-sg-1,My first security group1,add,ingress,tcp,22,22,0.0.0.0/0,SSH access ap-northeast-1,handson-cli-vpc,my-sg-1,My first security group1,add,egress,tcp,80,80,0.0.0.0/0,HTTP outbound ap-northeast-1,handson-cli-vpc,my-sg-1,My first security group1,add,ingress,-1,,,my-sg-3,Allow all ap-northeast-1,handson-cli-vpc,my-sg-2,My first security group2,add,ingress,tcp,22,22,0.0.0.0/0,SSH access ap-northeast-1,handson-cli-vpc,my-sg-2,My second security group2,add,ingress,tcp,80,80,10.0.0.0/16,HTTP outbound ap-northeast-1,handson-cli-vpc,my-sg-2,My second security group2,add,ingress,tcp,443,443,my-sg-1,HTTP inbound ap-northeast-1,handson-cli-vpc,my-sg-3,My third security group3,add,ingress,tcp,22,22,test_plefix_list,SSH access ap-northeast-1,handson-cli-vpc,my-sg-3,My third security group3,add,egress,-1,,,0.0.0.0/0, us-east-1,test1vpc,test-sg,Existing security group,add,ingress,tcp,3389,3389,10.0.2.0/24,exist us-east-1,test1vpc,test-sg,Existing security group,add,ingress,tcp,22,22,0.0.0.0/0, us-east-1,test1vpc,test-sg,Existing security group,add,ingress,tcp,443,443,0.0.0.0/0,add _EOF_
後はEC2とALBとRDSくらいかな。。。。
気が向いたらやるかもだけど、ありきたりなのであまりやる気が起きない。
コメント