こんにちわ、cloudpack磯辺です。

いつも、セキュリティグループのルールをコピーしたいと思っているのだが、今のAWS CLIであれば、以前にやったRDSのパラメータグループをコピーしたのと同じ方法でできるのではないかと思ったので、やってみた。

$ aws ec2 describe-security-groups \
  --filters 'Name=group-name,Values=src-sg' \
  --query 'SecurityGroups[].IpPermissions[]' \
  | tr -d '\d' \
  | xargs -I{} -- aws ec2 authorize-security-group-ingress --group-id sg-deadbeaf --ip-permissions '{}'

A client error (MissingParameter) occurred when calling the AuthorizeSecurityGroupIngress operation: Missing source specification: include source security group or CIDR information

エラーになってしまった。色々調べてみたら、以下の様な原因であることがわかった。

describe-security-groupsで取得したJSONには、IpRangesとUserIdGroupPairsの両方が項目として含まれている。セキュリティグループのルールは、対象としてCIDRを渡す他に、他のセキュリティグループを指定することができる。IpRangesには、IPアドレスが、UserIdGroupPairsには、セキュリティグループのIDが含まれる。

しかし、一つのルールにそれらが同時に含まれることはない。下記は、80/tcpを、IPアドレスとセキュリティグループを指定して定義したセキュリティグループのルールを取得したJSONの出力。別々のルールとして出力されていることが分かる。

% aws ec2 describe-security-groups --group-id 'sg-deadbeaf' --query 'SecurityGroups[].IpPermissions[]'
[
    {
        "ToPort": 80,
        "IpProtocol": "tcp",
        "IpRanges": [
            {
                "CidrIp": "192.0.2.1/32"
            }
        ],
        "UserIdGroupPairs": [],
        "FromPort": 80
    },
    {
        "ToPort": 80,
        "IpProtocol": "tcp",
        "IpRanges": [],
        "UserIdGroupPairs": [
            {
                "UserId": "nnnnnnnnnnnn",
                "GroupId": "sg-cafebabe"
            }
        ],
        "FromPort": 80
    }
]

authorize-security-group-ingressに渡す前に、値が含まれていない項目を除去すれば使うことができる。ということで、ちょっとしたフィルタを作った。

このフィルタを通すと、IpRangesまたはUserIdGroupPairsのうち、値が含まれていない項目を削除してくれる。また、xargsで処理しやすいように、1ルール1行に変換する。

% aws ec2 describe-security-groups --group-id 'sg-deadbeaf' --query 'SecurityGroups[].IpPermissions[]' | ruby ./repos/sgfilter/sgfilter.rb
'{"ToPort":80,"IpProtocol":"tcp","IpRanges":[{"CidrIp":"1n2.0.2.1/32"}],"FromPort":80}'
'{"ToPort":80,"IpProtocol":"tcp","UserIdGroupPairs":[{"UserId":"nnnnnnnnnnnn","GroupId":"sg-cafebabe"}],"FromPort":80}'

これを使って、下記のように、xargsを使って実行する。

$ aws ec2 describe-security-groups \
  --filters 'Name=group-name,Values=src-sg' \
  --query 'SecurityGroups[].IpPermissions[]' \
  | ruby sgfilter.rb \
  | xargs -I{} -- aws ec2 authorize-security-group-ingress --group-id sg-deadbeaf --ip-permissions '{}'

これで、src-sgに含まれる許可ルールが、sg-deadbeafに対してコピーされることになる。

元記事はこちらです。
[AWS] AWS CLIでセキュリティグループのルールをコピーする