事前に設定しておいたSGのIPアドレスの許可と同等の設定を他のIPアドレスにも設定したいという場合がしばしばあるのではないでしょうか。IPアドレスが複数、SGも複数、さらにはポートもいろいろ…となるとコンソール(またはAWS CLI)で設定すると多いときは50回だったり100回以上許可設定していくこともあります。

なんとかできないかと思い、AWS CLIにシェルスクリプトを組み合わせて用意しました。

以下、作業前後の状態確認と実際の作業コマンドです。
まずは現状の確認です。

$aws ec2 describe-security-group-rules --query "SecurityGroupRules[].[SecurityGroupRuleId,GroupId,IsEgress,IpProtocol,FromPort,ToPort,CidrIpv4]" --output text |grep aaa.aaa.aaa.aaa|sort -r |grep False
sgr-xxxxxxxxxxx   sg-xxxxxxxxxx1    False   tcp     80      80      aaa.aaa.aaa.aaa/32
sgr-xxxxxxxxxxx   sg-xxxxxxxxxx1    False   tcp     22      22      aaa.aaa.aaa.aaa/32
sgr-xxxxxxxxxxx   sg-xxxxxxxxxx2    False   tcp     22      22      aaa.aaa.aaa.aaa/32
sgr-xxxxxxxxxxx   sg-xxxxxxxxxx1    False   tcp     443     443     aaa.aaa.aaa.aaa/32
$

aaa.aaa.aaa.aaaというIPアドレスに対し、22,80,443ポートが許可されていると確認できます。そして、ひとつのSGは3つのポートが許可、もうひとつのSGは1つのポートが許可されています。これらと同じ設定を、他のIPアドレス(下記サンプルではbbb.bbb.bbb.bbb/32とccc.ccc.ccc.ccc/32)にもワンライナーで設定してみたいと思います。

↓実行コマンド

for port in $(aws ec2 describe-security-group-rules --query "SecurityGroupRules[].[SecurityGroupRuleId,GroupId,IsEgress,IpProtocol,FromPort,ToPort,CidrIpv4]" --output text | grep aaa.aaa.aaa.aaa/32| sort -r |grep False| awk '{print $6}'| uniq); do
    for sg in $(aws ec2 describe-security-group-rules --query "SecurityGroupRules[].[SecurityGroupRuleId,GroupId,IsEgress,IpProtocol,FromPort,ToPort,CidrIpv4]" --output text | grep aaa.aaa.aaa.aaa/32|grep $port | sort -r| awk '{print $2}'); do
       for object in bbb.bbb.bbb.bbb/32 ccc.ccc.ccc.ccc/32; do
           aws ec2 authorize-security-group-ingress --group-id "$sg" --ip-permissions IpProtocol=tcp,FromPort=$port,ToPort=$port,IpRanges='[{CidrIp='"$object"',Description="iret"}]'
        done
        read -p "$port $sg done. continue? " 
    done
done

↓実行中のコマンド出力イメージ

{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-xxxxxxxxxxx",
            "GroupId": "sg-xxxxxxxxxxx",
            "GroupOwnerId": "000000000",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 80,
            "ToPort": 80,
            "CidrIpv4": "bbb.bbb.bbb.bbb/32",
            "Description": "iret"
        }
    ]
}
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "sgr-xxxxxxxxxxx",
            "GroupId": "sg-xxxxxxxxxxx",
            "GroupOwnerId": "000000000",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 80,
            "ToPort": 80,
            "CidrIpv4": "ccc.ccc.ccc.ccc/32",
            "Description": "iret"
        }
    ]
}
80 sg-xxxxxxxxxx1 done. continue? 

最初の現状確認のコマンドから、どのポートに対して許可されているかを調べて抜き出し、portという変数でループさせています。次にそのポートの許可はどのSGについての話なのかを抜き出します。最後に、authorize-security-group-ingressというCLIコマンドを追加したいIPごとに実行しています。私は心配性なので、意図しない実行結果を見つけてしまうことも考え「read -p "$port $sg done. continue? " 」と聞いてもらうことで、途中までの結果を見ながら続行するか中止できるかを都度選べるようにしています。

最後に改めて状態を確認します。最初と同様の確認のコマンドをIPごとに打つか、複数のIPアドレスをまとめて下記のように打って確認します。

aws ec2 describe-security-group-rules --query "SecurityGroupRules[].[SecurityGroupRuleId,GroupId,IsEgress,IpProtocol,FromPort,ToPort,CidrIpv4]" --output text |grep -e aaa.aaa.aaa.aaa -e bbb.bbb.bbb.bbb -e ccc.ccc.ccc.ccc|sort -r |grep False

最初の現状確認のコマンドの方が見比べやすいかとは思いますが、上記のIPアドレスをまとめたコマンドの方がコマンド数が少ないので楽なこともあり、状況に応じて使い分けるといいかと思っています。

上記はあくまで一例ですので、実際は環境ごとに意図通りのコマンドが打てそうかを確認していく必要があります。今回はdescribeのAWS CLIとfor文を組み合わせました。その他にも、シェルスクリプトと組み合わせたAWS CLIコマンドを作ることで、作業ミスの可能性を減らし、作業時間を短縮できる可能性があります。