Playing with Powershell and JSON (and Amazon and Firewalls)
In this post we'll take a look at parsing and manipulating JSON in Powershell.
Taking a look at the problem at hand, my client was using AWS Route53 load balancers, and wanted to permit access to (only) the appropriate services so that the load balancers could do "health checks" on them.
Simple enough, I said, the address ranges are all public (https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/route-53-ip-addresses.html). The download (https://ip-ranges.amazonaws.com/ip-ranges.json) is a JSON file, and looks like this:
{
"syncToken": "1670257989",
"createDate": "2022-12-05-16-33-09",
"prefixes": [
{
"ip_prefix": "3.2.34.0/26",
"region": "af-south-1",
"service": "AMAZON",
"network_border_group": "af-south-1"
},
{
"ip_prefix": "3.5.140.0/22",
"region": "ap-northeast-2",
"service": "AMAZON",
"network_border_group": "ap-northeast-2"
},
{
"ip_prefix": "13.34.37.64/27",
"region": "ap-southeast-4",
"service": "AMAZON",
"network_border_group": "ap-southeast-4"
},
{ ... (and so on) ...
At was at that point that I realized a "grep" wasn't going to work for this, and either I had do this manually (which would mean I'd miss one for sure) or import this JSON file into something I could use - in my case lately that's PowerShell. In this case we won't be writing a full-on script, we'll be using PowerShell as a working environment / scratch pad and work towards our solution rather than as a programming language.
Easy enough, let's start import the file, and convert the JSON into PowerShell objects:
$a = get-content -raw -path .\ipranges.json | convertfrom-json
Looking at a sample entry, the data (and solving our problem) is now much simpler:
$a.prefixes[3]
ip_prefix region service network_border_group
--------- ------ ------- --------------------
13.34.65.64/27 il-central-1 AMAZON il-central-1
To just get the requisite services and regions (us-east and us-west):
$a.prefixes | where-object {$_.region -like "us-*" -and $_.service -eq "ROUTE53_HEALTHCHECKS"}
ip_prefix region service network_border_group
--------- ------ ------- --------------------
107.23.255.0/26 us-east-1 ROUTE53_HEALTHCHECKS us-east-1
54.243.31.192/26 us-east-1 ROUTE53_HEALTHCHECKS us-east-1
54.183.255.128/26 us-west-1 ROUTE53_HEALTHCHECKS us-west-1
54.241.32.64/26 us-west-1 ROUTE53_HEALTHCHECKS us-west-1
54.244.52.192/26 us-west-2 ROUTE53_HEALTHCHECKS us-west-2
54.245.168.0/26 us-west-2 ROUTE53_HEALTHCHECKS us-west-2
What happened? Well nothing, we got a lot of "access denied" messages on the firewall ACL. I turns out that at this point in time, none of the load balancer health checks are actually coming from either us-east or us-west, they're all in the "global" range - none of the services we were playing with are datacenter specific (yet)
So I updated my one-liner to look like:
$a.prefixes | where-object {($_.region -like "us-*" -or $_.region -like "GLOBAL") -and $_.service -eq "ROUTE53_HEALTHCHECKS"}
ip_prefix region service network_border_group
--------- ------ ------- --------------------
15.177.0.0/18 GLOBAL ROUTE53_HEALTHCHECKS GLOBAL
107.23.255.0/26 us-east-1 ROUTE53_HEALTHCHECKS us-east-1
54.243.31.192/26 us-east-1 ROUTE53_HEALTHCHECKS us-east-1
54.183.255.128/26 us-west-1 ROUTE53_HEALTHCHECKS us-west-1
54.241.32.64/26 us-west-1 ROUTE53_HEALTHCHECKS us-west-1
54.244.52.192/26 us-west-2 ROUTE53_HEALTHCHECKS us-west-2
54.245.168.0/26 us-west-2 ROUTE53_HEALTHCHECKS us-west-2
To just get the subnets to put into the firewall rule:
($a.prefixes | where-object {($_.region -like "us-*" -or $_.region -like "GLOBAL") -and $_.service -eq "ROUTE53_HEALTHCHECKS"}).ip_prefix
15.177.0.0/18
107.23.255.0/26
54.243.31.192/26
54.183.255.128/26
54.241.32.64/26
54.244.52.192/26
54.245.168.0/26
Success!
The final firewall rules now look like:
object-group network AWS_ROUTE53_HEALTHCHECKS
network-object 54.183.255.128 255.255.255.192
network-object 54.241.32.64 255.255.255.192
network-object 54.244.52.192 255.255.255.192
network-object 54.245.168.0 255.255.255.192
network-object 107.23.255.0 255.255.255.192
network-object 54.243.31.192 255.255.255.192
network-object 15.177.0.0 255.255.192.0
object-group network ADFS-TARGETS
network-object object SITE01-ADFS
network-object object SITE02-ADFS
access-list outside_acl line 37 remark AWS Route53 Load Balancer Health Checks
access-list outside_acl line 38 extended permit tcp object-group AWS_ROUTE53_HEALTHCHECKS object-group ADFS-TARGETS eq https
This would have taken roughly the same time to do manually, except (knowing myself) I'd be sure to miss one line or drop a digit during a copy/paste or something. Plus this is something we'll want to revisit periodically - as the AWS subnets change we'll need to update the firewall rules of course. And of course this is also a code snip I can use going forward for all kinds of JSON data, not just this specific thing.
I hope this is a useful thing for your toolbox - if you've got a similar situation with a different slant (JSON, XML or some other format) by all means share, post to our comment form below!
===============
Rob VandenBrink
rob@coherentsecurity.com
Comments
Vincent T
Dec 28th 2022
2 years ago
Rob VandenBrink
Dec 28th 2022
1 year ago
dk8e
Dec 29th 2022
1 year ago
PS D:\Users\xxxx> Get-AWSPublicIpAddressRange -ServiceKey Route53
IpPrefix IpAddressFormat Region Service
-------- --------------- ------ -------
52.95.110.0/24 Ipv4 GLOBAL ROUTE53
205.251.192.0/21 Ipv4 GLOBAL ROUTE53
63.246.114.0/23 Ipv4 GLOBAL ROUTE53
DT
Jan 5th 2023
1 year ago