Playing with Powershell and JSON (and Amazon and Firewalls)

Published: 2022-12-28. Last Updated: 2022-12-28 02:46:48 UTC
by Rob VandenBrink (Version: 1)
4 comment(s)

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

Keywords: AWS json powershell
4 comment(s)

Comments

I guess I'd happily have used a few lines of PHP code for that. Oh well, use your weapon of choice...
Cool, I'd expect that Python would be a more common choice, and is what I would have gone to first even a year ago. Just wanted to illustrate that the PowerShell / Infosec folks have an option for JSON as well.

Some firewalls allow you to automate this without any custom scripting. For example: https://docs.paloaltonetworks.com/resources/edl-hosting-service
It's worth noting that if you have the AWS Powershell commandlets installed, you can simplify this to:

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

Diary Archives