🐱
[bash] AWS CLIでセキュリティグループのルール追加・削除
概要
- AWS CLIを用いて既存のセキュリティグループのルールを追加、削除したい
- ルールが複数あるとawsコマンドを組み立てる手間がかかる
- bashスクリプトで複数のルールに適用させる
- ルールはリストファイルにして、CSV形式
- 第1引数にアクション(add/del)、第2引数にインバウンドかアウトバンド方向(in/out)、第3引数にリストファイル
- 第4引数に実際にAWS CLIコマンドを実行するオプション(-y)
コード
- ファイル名: aws-security-group_rule.sh
- GitHub https://github.com/dsta50/aws-security-group_rule
- aws-security_group_rule.sh <add|del> <in|out> <rule_list(csv)> [-y]
#!/bin/bash
LOG_DIR=$(cd $(dirname ${0}); pwd)/log
LOGFILE=${LOG_DIR}/$(basename $0)_$(date '+%Y%m%d').log
AWSCLI_CMD='aws ec2'
USAGE="$0 <add|del> <in|out> <listfile(csv)> [-y]"
# Argument
ACTION=$1
DIRECTION=$2
RULE_LIST=$3
EX_OPTIN=$4
# Argument Count Check 引数の数
if [ $# -ne 3 -a $# -ne 4 ]; then
echo -e "Error: Invalid number of arguments"
echo -e "Usage: ${USAGE}"
exit 1
fi
# Existence of list file check リストファイルの有無
if [ ! -f "${RULE_LIST}" ]; then
echo "${RULE_LIST} does not exist."
exit 1
fi
# Set subcommand for inbaund/outband rule
case "${DIRECTION}" in
in )
SUBCOM_TMP="ingress"
;;
out )
SUBCOM_TMP="egress"
;;
* )
echo -e "Error: Invalid argument: ${DIRECTION}"
echo -e "Usage: ${USAGE}"
exit 2
;;
esac
# Set subcommand for delet/add rule ルールの作成/削除のサブコマンドを設定
case ${ACTION} in
add )
SUBCMD="authorize-security-group-${SUBCOM_TMP}"
;;
del )
SUBCMD="revoke-security-group-${SUBCOM_TMP}"
;;
* )
echo -e "Error: Invalid argument: ${ACTION}"
echo -e "Usage: ${USAGE}"
exit 2
;;
esac
# Check logfile directory and make
test ! -d ${LOG_DIR} && mkdir ${LOG_DIR}
echo -e "" >> ${LOGFILE}
echo -e "# Running scripts. $(uname -n)@$(whoami) Time: $(date '+%Y-%m-%d %H:%M:%S')" | tee -a ${LOGFILE}
# function: AWS-CLI commnd create
function func_create_cmd() {
SG_ID=$1
PROTOCOL=$2
FROM_PORT=$3
TO_PORT=$4
DEST_SRC=$5
DESCRIPTION=$6
# Set subcommand parameter: Source/destination 送信先/送信元のパラメータを設定
if [[ ${DEST_SRC} =~ sg-[[:alnum:]]+ ]]; then
# SG-ID
SUBCMD_PRM1='UserIdGroupPairs'
SUBCMD_PRM2='GroupId'
elif [[ ${DEST_SRC} =~ [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+ ]]; then
# IPv4 CIDER
SUBCMD_PRM1='IpRanges'
SUBCMD_PRM2='CidrIp'
elif [[ ${DEST_SRC} =~ [0-9a-fA-F:]+/[0-9]+ ]]; then
# IPv6 CIDER
SUBCMD_PRM1='Ipv6Ranges'
SUBCMD_PRM2='CidrIpv6'
fi
# Set subcommand parameter: Description 説明を設定、ルール削除する時は空白
if [[ ${DESCRIPTION} == "" ]]; then
SUBCMD_PRM3=''
else
SUBCMD_PRM3=",Description="${DESCRIPTION}""
fi
# '-1' for protocol means all traffic, no need to specify port
if [[ ${PROTOCOL} =~ -1 ]]; then
SUBCOMD_TMP="${SUBCMD} --group-id ${SG_ID} --ip-permissions IpProtocol=${PROTOCOL},${SUBCMD_PRM1}='[{${SUBCMD_PRM2}=${DEST_SRC}"${SUBCMD_PRM3}"}]'"
else
SUBCOMD_TMP="${SUBCMD} --group-id ${SG_ID} --ip-permissions IpProtocol=${PROTOCOL},FromPort=${FROM_PORT},ToPort=${TO_PORT},${SUBCMD_PRM1}='[{${SUBCMD_PRM2}=${DEST_SRC}"${SUBCMD_PRM3}"}]'"
fi
# Assembling commands
CMD="${AWSCLI_CMD} ${SUBCOMD_TMP}"
return 0
}
# Main
# Read and process rules from list file リストファイルからルールを読み取って処理を行う
while IFS=',' read -r SG_ID PROTOCOL FROM_PORT TO_PORT DEST_SRC DESCRIPTION TEMP
do
# Remove "(Double quotation) from field
SG_ID=$(echo "${SG_ID}" | sed 's/"//g')
PROTOCOL=$(echo "${PROTOCOL}" | sed 's/"//g')
FROM_PORT=$(echo "${FROM_PORT}" | sed 's/"//g')
TO_PORT=$(echo "${TO_PORT}" | sed 's/"//g')
DEST_SRC=$(echo "${DEST_SRC}" | sed 's/"//g')
# Check field sg-id
if [[ ! ${SG_ID} =~ sg-[[:alnum:]]+ ]]; then
echo "Skip: "${SG_ID}", "${PROTOCOL}", "${FROM_PORT}", "${TO_PORT}", "${DEST_SRC}""
continue
fi
if [[ ${DESCRIPTION} =~ \# ]]; then
DESCRIPTION=''
fi
case "${EX_OPTIN}" in
"-y" )
if [[ ${ACTION} == "add" ]]; then
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}" "${DESCRIPTION}"
echo -e "Add command: ${CMD}" 2>&1 | tee -a ${LOGFILE}
elif [[ ${ACTION} == "del" ]]; then
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}"
echo -e "Delete command: ${CMD}" 2>&1 | tee -a ${LOGFILE}
fi
eval ${CMD} 2>&1 | tee ${LOGFILE}.tmp
# Remove prefix when running debug mode
grep -v '^++' ${LOGFILE}.tmp >> ${LOGFILE}
rm -f ${LOGFILE}.tmp
;;
* )
if [[ ${ACTION} == "add" ]]; then
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}" "${DESCRIPTION}"
elif [[ ${ACTION} == "del" ]]; then
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}"
fi
echo ${CMD} 2>&1 | tee -a ${LOGFILE}
;;
esac
done < <(awk -F',' '{ if($1~"^[^#]") print $0}' "${RULE_LIST}" | tr -d '\r')
exit 0
- IFS=',' によって、CSVファイルの各行をカンマで区切って読み込んでる。
- CSVファイル内のカンマの扱いに注意が必要
ヘッダ情報
- 何をするスクリプトなのかはっきりわかるようにする
#!/bin/bash
# Usage:
# aws-security_group_rule.sh <add|del> <in|out> <rule_list(csv)> [-y]
# add/del: Specify "add" to add rules or "del" to delete rules.
# in/out: Inboud or Outbound
# rule_list(csv): The path to the CSV file containing the list of rules to add or delete.
# -y: Actually run with AWS CLI
# Description:
# This script can add or delete rules for existing security groups using the AWS CLI.
# The CSV file should include the security group ID for the target security group.
# <group-id>,<protocol>,<from-port>,<to-port>,<Destination|Source(CIDR/SGID)>,<DESCRIPTION>
#
memo
- teaコマンドを使うことでログ出力と画面出力できるようにした
- 検証済み、dryrunが実行できるかなど
'--dry-run'は公式ドキュメントによると権限があるかのチェックのみで、構文をチェックはなく実用性がないため、削除した - ヘッダ情報やコメント行の修正
ルール削除のスクリプト
- ルールの削除だけを行う
- オプション[-y]なしだとAWS CLIのコマンドが表示し、ログファイルに記録される
- オプション[-y]を付けると、実際にAWS CLIで実行される
#!/bin/bash
# Usage:
# sg_delrule.sh <in|out> <rule_list(csv)> [-y]
# in/out: Inboud or Outbound
# rule_list.csv: The path to the CSV file containing the list of rules to delete.
# -y: Actually run with AWS CLI
# Description:
# This script can delete rules for existing security groups using the AWS CLI.
# The CSV file should include the security group ID for the target security group.
# <group-id>,<protocol>,<from-port>,<to-port>,<CIDR/SGID>
#
LOG_DIR=$(cd $(dirname ${0}); pwd)/log
LOGFILE=${LOG_DIR}/$(basename $0)_$(date '+%Y%m%d-%H').log
AWSCLI_CMD='aws ec2'
USAGE="$0 <in|out> <listfile(csv)> [-y]"
DIRECTION=$1
RULE_LIST=$2
EX_OPTIN=$3
# Argument Count Check
if [ $# -ne 2 -a $# -ne 3 ]; then
echo -e "Error: Invalid number of arguments"
echo -e "Usage: ${USAGE}"
exit 1
fi
# Existence of list file check
if [ ! -f "${RULE_LIST}" ]; then
echo "${RULE_LIST} does not exist."
exit 1
fi
# Set subcommand for inbaund/outband rule
case "${DIRECTION}" in
in)
SUBCOM_TMP="ingress" ;;
out)
SUBCOM_TMP="egress" ;;
*)
echo -e "Error: Invalid argument: ${DIRECTION}"
echo -e "Usage: ${USAGE}"
exit 1 ;;
esac
# Set subcommand for delete rule
SUBCMD="revoke-security-group-${SUBCOM_TMP}"
# Check logfile directory and make
test ! -d ${LOG_DIR} && mkdir ${LOG_DIR}
echo -e "" >> ${LOGFILE}
echo -e "# Running scripts. $(uname -n)@$(whoami) Time: $(date '+%Y%m%d-%H:%M:%S')" | tee -a ${LOGFILE}
# function: AWS-CLI commnd create
function func_create_cmd() {
SG_ID=$1
PROTOCOL=$2
FROM_PORT=$3
TO_PORT=$4
DEST_SRC=$5
# Set subcommand parameter: Source/destination
if [[ ${DEST_SRC} =~ sg-[[:alnum:]]+ ]]; then
# SG-ID
SUBCMD_PRM1='UserIdGroupPairs'
SUBCMD_PRM2='GroupId'
elif [[ ${DEST_SRC} =~ [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+ ]]; then
# IPv4 CIDER
SUBCMD_PRM1='IpRanges'
SUBCMD_PRM2='CidrIp'
elif [[ ${DEST_SRC} =~ [0-9a-fA-F:]+/[0-9]+ ]]; then
# IPv6 CIDER
SUBCMD_PRM1='Ipv6Ranges'
SUBCMD_PRM2='CidrIpv6'
fi
# '-1' for protocol means all traffic, no need to specify port
if [[ ${PROTOCOL} =~ -1 ]]; then
SUBCOMD_TMP="${SUBCMD} --group-id ${SG_ID} --ip-permissions IpProtocol=${PROTOCOL},${SUBCMD_PRM1}='[{${SUBCMD_PRM2}=${DEST_SRC}}]'"
else
SUBCOMD_TMP="${SUBCMD} --group-id ${SG_ID} --ip-permissions IpProtocol=${PROTOCOL},FromPort=${FROM_PORT},ToPort=${TO_PORT},${SUBCMD_PRM1}='[{${SUBCMD_PRM2}=${DEST_SRC}}]'"
fi
# Assembling commands
CMD="${AWSCLI_CMD} ${SUBCOMD_TMP}"
}
# Main
# Read and process rules from list file
while IFS=',' read -r SG_ID PROTOCOL FROM_PORT TO_PORT DEST_SRC TEMP
do
# Remove "(Double quotion) from field
SG_ID =$(echo "${SG_ID}" | sed 's/"//g')
PROTOCOL=$(echo "${PROTOCOL}" | sed 's/"//g')
FROM_PORT=$(echo "${FROM_PORT}" | sed 's/"//g')
TO_PORT=$(echo "${TO_PORT}" | sed 's/"//g')
DEST_SRC=$(echo "${DEST_SRC}" | sed 's/"//g')
# Check field sg-id
if [[ ! ${SG_ID} =~ sg-[[:alnum:]]+ ]]; then
echo "Skip: "${SG_ID}", "${PROTOCOL}", "${FROM_PORT}", "${TO_PORT}", "${DEST_SRC}""
continue
fi
case "${EX_OPTION}" in
"-y" )
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}"
echo -e "Delete command: ${CMD}" 2>&1 | tee -a ${LOGFILE}
eval ${CMD} 2>&1 | tee ${LOGFILE}.tmp
# Remove prefix when running debug mode
grep -v '^++' ${LOGFILE}.tmp >> ${LOGFILE}
rm -f ${LOGFILE}.tmp
;;
* )
func_create_cmd "${SG_ID}" "${PROTOCOL}" "${FROM_PORT}" "${TO_PORT}" "${DEST_SRC}"
echo -e "${CMD}" 2>&1 | tee -a ${LOGFILE}
;;
esac
done < <(awk -F',' '{ if($1~"^[^#]") print $0}' "${RULE_LIST}" | tr -d '\r')
exit 0
Discussion