I'm having difficulty filtering AWS CLI describe-security-groups output
Goal: Find all SGs with ingress rules on port 22 with cidr 0.0.0.0/0
Amazons' own docs provide an example, but state there's a limitation with their query in that it will first filter the entire data set for port 22 then filter that entire data set for 0.0.0.0/0. What this means is that SGs with the following rules will still trigger:
ingress 22 sg-12345678
ingress 443 0.0.0.0/0
This completely defeats the purpose of the filtering, and I'm not even sure why Amazon provides that example with a heading of "To describe security groups that have specific rules"
Route 1: aws cli query first then jq
This route is based off what I found here: https://github.com/aws/aws-cli/issues/971
aws ec2 describe-security-groups --output json --query 'SecurityGroups[*].[GroupName,GroupId,IpPermissions[?ToPort==`22`].[IpRanges[?CidrIp==`0.0.0.0/0`]]]'
Which provides a list of all security groups, but showing nested data for any SGs with 22 0.0.0.0/0 (and successfully ignoring any 0.0.0.0/0 ACLs for other ports) In the output below, SG1 is what I'm interested, and SG2/SG3 needs to be filtered out.
[
[
"SG 1",
"sg-11111111",
[
[
[
{
"CidrIp": "0.0.0.0/0"
}
]
]
]
],
[
"SG 2",
"sg-22222222",
[
[
[]
]
]
],
[
"SG 3",
"sg-33333333",
[]
]
]
This is a great first step as I've eliminated 0.0.0.0/0 ACLs that aren't associated with port 22. But as I try to run jq to simply remove entries that have empty data sets, I'm having difficulty cause all the keys have been stripped.
Route 2: jq un-queried CLI output
I've been unable to get away from the pitfall of the original AWS example by using jq from the start, where I can first query for all SGs that contain port 22, then query for any ACLs of 0.0.0.0/0, which of course gives me false positives. Due to the stream nature of jq, I haven't figured out how to check condition A (port 22) then check condition B (0.0.0.0/0) only on items related to condition A.
Here's some sanitized raw CLI output of 2 SGs, again, I need to get the first one without triggering a false positive on the 2nd
{
"SecurityGroups": [
{
"Description": "SG 1",
"IpPermissions": [
{
"PrefixListIds": [],
"FromPort": 22,
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"ToPort": 22,
"IpProtocol": "tcp",
"UserIdGroupPairs": [],
"Ipv6Ranges": []
}
],
"GroupName": "SG 1",
"VpcId": "vpc-12345678",
"OwnerId": "1234567890",
"GroupId": "sg-11111111"
},
{
"Description": "SG 2",
"IpPermissions": [
{
"PrefixListIds": [],
"FromPort": 22,
"IpRanges": [],
"ToPort": 22,
"IpProtocol": "tcp",
"UserIdGroupPairs": [
{
"UserId": "1234567890",
"GroupId": "sg-abcdefab"
}
],
"Ipv6Ranges": []
},
{
"PrefixListIds": [],
"FromPort": 443,
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"ToPort": 443,
"IpProtocol": "tcp",
"UserIdGroupPairs": [],
"Ipv6Ranges": []
}
],
"GroupName": "SG 2",
"VpcId": "vpc-12345678",
"OwnerId": "1234567890",
"GroupId": "sg-22222222"
}
]
}
You need to use advanced JMESPath conditions. See if the below cli command satisfies what you are asking.
aws ec2 describe-security-groups \
--filters "Name=ip-permission.to-port,Values=22" \
--query 'SecurityGroups[?IpPermissions[?ToPort==`22` && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]].{GroupId: GroupId, GroupName: GroupName}' \
--output json \
--region us-east-1
Here is a jq filter which will return only SecurityGroups with an IpPermission with FromPort=22 and an IpRange CidrIp of "0.0.0.0/0":
.SecurityGroups[]
| select(.IpPermissions[] | .FromPort == 22 and .IpRanges[].CidrIp == "0.0.0.0/0")
Sample Run (assuming filter in filter.jq
and data in data.json
)
$ jq -M -f filter.jq data.json
{
"Description": "SG 1",
"IpPermissions": [
{
"PrefixListIds": [],
"FromPort": 22,
"IpRanges": [
{
"CidrIp": "0.0.0.0/0"
}
],
"ToPort": 22,
"IpProtocol": "tcp",
"UserIdGroupPairs": [],
"Ipv6Ranges": []
}
],
"GroupName": "SG 1",
"VpcId": "vpc-12345678",
"OwnerId": "1234567890",
"GroupId": "sg-11111111"
}
Try it online at jqplay.org
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With