LoginSignup
2
2

More than 5 years have passed since last update.

AWS CLIをWindows(でpipを使わずに)、cygwin環境下で使えるようにして、自宅IP(非固定)が変わったらスクリプト一発でEC2のセキュリティグループをアップデートする

Last updated at Posted at 2017-10-22

何言ってるかよくわからない?俺もなんでこんなことしてるのかようわからん。。:frowning2:

趣味程度に使うAWSなのでそんなにがっつり使ってるわけではないんだけど、windows(cygwin)環境下で使えるようにしたのでメモ ※python(pip)使ったほうがいいよ?→正解

環境

Windows10(64bit)
cygwin
※jsonの整形に jq と jo を使うので、cygwinから使えるようにパス通しておく

手順

AWS CLI for Windowsを入手

https://aws.amazon.com/jp/cli/
32bitか64bit好きなほう持ってくる
Windows上でてきとうなところへ展開しインストール。どこでもいい。
※cygwinから辿れるパスで

cygwinから使えるようにする

展開したディレクトリに aws.exe があるので、こいつをcygwin上で実行できるようにする。
自分は単純に展開したディレクトリを.bashrcに追記してパス通した。
ついでにaliasに書き足して aws-cli で実行できるように。
※あとで気付いたけどこのaliasいらなくてそのままパス通して aws で実行するだけでよかった

.bashrc
# for aws-cli
AWSCLI_HOME=[aws-cliを展開したディレクトリ、cygwinが辿れるように書く]
export PATH=$PATH:$AWSCLI_HOME
alias aws-cli='aws.exe'

これでcygwinからaws-cliを実行できるようになった。
configure忘れずに。

$ aws-cli --version
aws-cli/1.11.175 Python/2.7.9 Windows/8 botocore/1.7.33

やりたいこと

EC2インスタンスに設定しているセキュリティグループについて、自宅のIPが固定じゃないのでIPが変わったらスクリプト一発でセキュリティグループをアップデートしたい。以下の流れで実行する。

・新しいIPを取得する
インターネットに公開されてる自分のGIPを教えてくれるサービスにcurlで接続しレスポンスボディから抜き出す
取得したIPの末尾に /32 を補完してCIDR表記をゲット(具体的なやりかたは省略)

・セキュリティグループをアップデートするためのjsonを作る
aws-cli ec2 authorize-security-group-ingress
が使いたいコマンド。リファレンス → http://docs.aws.amazon.com/cli/latest/reference/ec2/authorize-security-group-ingress.html

使い方のイメージはリファレンスにある

$ aws ec2 authorize-security-group-ingress --group-id sg-123abc12 --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 3389, "ToPort": 3389, "IpRanges": [{"CidrIp": "203.0.113.0/24", "Description": "RDP access from NY office"}]}]'

これなんだけど、ちょっとごちゃごちゃやってみたかぎり、投げるjsonをシェル変数に埋めてそのままPOSTするのムリっぽい(シングルクォートとかのエスケープを頑張ればいける・・?)ので、おとなしくjsonをファイルに生成して、それを --cli-input-json オプションに渡すのがよさそう。
※どういうjsonを投げたのか?をファイルとして残しておけるしね!

というわけで、シェルでjsonを生成する。
joコマンドを使う。 https://qiita.com/yangci/items/4a7602df4faae5773532 を参照。

生成する必要があるjsonフォーマットは以下の内容。


{
    "GroupId": "xx-xxxxxxx",
    "IpPermissions": [
        {
            "IpProtocol": "-1", #「全てのプロトコル」は -1 で指定
            "IpRanges": [
                {
                    "CidrIp": "203.0.113.0/24", #取得した自分のIP ※このIPはリファレンスに書いてあったもの
                    "Description": "aws-cli(test)" #説明文
                }
            ]
        }
    ]
}

以下のjoコマンドで生成する

TARGET_INFO=$(jo -p GroupId="${GROUP_ID}" IpPermissions[]=$(jo IpProtocol="${IP_PROTOCOL}" IpRanges[]=$(jo CidrIp="${MYIP}" Description="MyHomeIP($TODAY)")))

このjoだと、${IP_PROTOCOL}に"-1"をいれてもどうもjoに勝手に -1 に変えられてしまう(ダブルクォートが亡き者にされる)ので、sedを一個かまして無理やりダブルクォートを足す。

TARGET_INFO=$(jo -p GroupId="${GROUP_ID}" IpPermissions[]=$(jo IpProtocol="${IP_PROTOCOL}" IpRanges[]=$(jo CidrIp="${MYIP}" Description="MyHomeIP($TODAY)")))
echo ${TARGET_INFO} | jq '.' > ${TARGET_INFO_JSON}
TMP=$(cat ${TARGET_INFO_JSON} | sed -e "s/-1/\"-1\"/g")
echo -e "${TMP}" >${TARGET_INFO_JSON}

最初jqはいらない予定だったけど、ここでjsonの整形が必要になったので最初のjoの出力時点で再度jqで整形しておく。
joの -p オプションがこれやってくれる気がしたけど、うまく動かなかったのでそのままjqにパイプで渡してる

参考までに、--generate-cli-skeletonの出力は以下

$ aws ec2 authorize-security-group-ingress --generate-cli-skeleton
{
    "CidrIp": "",
    "FromPort": 0,
    "GroupId": "",
    "GroupName": "",
    "IpPermissions": [
        {
            "FromPort": 0,
            "IpProtocol": "",
            "IpRanges": [
                {
                    "CidrIp": "",
                    "Description": ""
                }
            ],
            "Ipv6Ranges": [
                {
                    "CidrIpv6": "",
                    "Description": ""
                }
            ],
            "PrefixListIds": [
                {
                    "Description": "",
                    "PrefixListId": ""
                }
            ],
            "ToPort": 0,
            "UserIdGroupPairs": [
                {
                    "Description": "",
                    "GroupId": "",
                    "GroupName": "",
                    "PeeringStatus": "",
                    "UserId": "",
                    "VpcId": "",
                    "VpcPeeringConnectionId": ""
                }
            ]
        }
    ],
    "IpProtocol": "",
    "SourceSecurityGroupName": "",
    "SourceSecurityGroupOwnerId": "",
    "ToPort": 0,
    "DryRun": true
}

最終的にcygwinで実行するシェルスクリプト全体としてはこんな感じ。

update_securitygroup_myip.sh
#!/bin/bash
PATH=[いい感じにパス通す]
export PATH

### SCRIPT ENV ###
retval=0

SCRIPT_DIR=[スクリプトを設置してるディレクトリ]
LOG_DIR=${SCRIPT_DIR}/log
JSON_DIR=${SCRIPT_DIR}/json

TODAY=$(date '+%Y%m%d')
TIME=$(date '+%H%M%S')
MYIP="$(getMyIP.sh)/32"
TARGET_INFO_JSON=${TODAY}_${TIME}.json

cd ${SCRIPT_DIR}

### AWS ENV ###
retval=0
GROUP_ID="xx-xxxxxxxx"
IP_PROTOCOL="-1"

TARGET_INFO=$(jo -p GroupId="${GROUP_ID}" IpPermissions[]=$(jo IpProtocol="${IP_PROTOCOL}" IpRanges[]=$(jo CidrIp="${MYIP}" Description="MyHomeIP($TODAY)")))
echo ${TARGET_INFO} | jq '.' > ${TARGET_INFO_JSON}
TMP=$(cat ${TARGET_INFO_JSON} | sed -e "s/-1/\"-1\"/g")
echo -e "${TMP}" >${TARGET_INFO_JSON}
#cat ${TARGET_INFO_JSON}

### main ###
RESULT=$(aws ec2 authorize-security-group-ingress --cli-input-json file://${TARGET_INFO_JSON} 2>&1 )
retval=$?

#retvalが0以外だったら、ログディレクトリに出しておく
if [ ! $retval -eq 0 ] ; then
  echo $0 > ${LOG_DIR}/${TODAY}_${TIME}.log
  echo $RESULT >> ${LOG_DIR}/${TODAY}_${TIME}.log
  echo "error , watch log -> ${LOG_DIR}/${TODAY}_${TIME}.log" 1>&2
fi

#生成したjsonを退避
mv ${TARGET_INFO_JSON} ${JSON_DIR}/

exit $retval

実行

・成功

$ ./update_securitygroup_myip.sh

※特に出力なし。json/配下に、--input-cli-jsonで渡したjsonが残ってる。

・失敗(わざと2回目やると、重複するルールを登録することになるので失敗する)

$ ./update_securitygroup_myip.sh
error , watch log -> [ログディレクトリ]/20171022_192416.log

ログを確認する

$ cat [ログディレクトリ]/20171022_192416.log
./update_securitygroup_myip.sh
 An error occurred (InvalidPermission.Duplicate) when calling the AuthorizeSecurityGroupIngress operation: the specified rule "peer: xxx.xxx.xxx.xxx/32, ALL, ALLOW" already exists

ちゃんと、「このIPのルール既にあるよ」のエラーを返している。ちなみに終了ステータスは255.

TO DO

・不要になったIPをセキュリティグループから削除する ※上のスクリプトの中でいっしょにやるべき

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2