Skip to content

Routing SaaS application traffic through a gateway

Some SaaS platforms, such as ITGlue, let you restrict account access to a list of approved IP addresses. You can use an Enclave gateway with a known static IP address to route traffic to those platforms, then lock access down to only that IP. The challenge is that many SaaS providers don't publish static IP addresses for their services, so the IP addresses behind their DNS records can change without notice.

This script resolves a set of DNS hostnames into IP addresses and writes them as subnet filtering rules on an Enclave gateway policy via the REST API. Run it on a schedule and your gateway policy stays in sync with the provider's current infrastructure.

Prerequisites

  • An Enclave API key
  • Your Organisation ID
  • A configured Enclave gateway with a gateway access policy that routes 0.0.0.0/0
  • The DNS hostnames of the SaaS service you want to route (e.g. customer1.eu.itglue.com)

How it works

The script takes one or more DNS hostnames as input, resolves each to its current set of IPv4 addresses, and builds a list of IP-based subnet filtering rules. It then searches for the named gateway policy using the Enclave API, and patches the policy's allowed IP ranges with the resolved addresses. Only traffic destined for those IPs will be routed through the gateway - everything else continues to use the client's default route.

A -test flag lets you preview the changes without modifying the policy.

The script

Save the following script as a .ps1 file.

  • -orgId, the organisation to run queries against.
  • -apiKey, the Enclave API key. If you prefer not to put your API key on the command line, set the ENCLAVE_API_KEY environment variable instead.
  • -policyName, the name of the gateway policy to update.
  • -dnsNames, one or more DNS hostnames to resolve into IP addresses.
  • -test, prints what the script would do without making changes.
Param(
    [Parameter(Mandatory=$true)]
    [string]$orgId,

    [Parameter()]
    [string]$apiKey = "",

    [Parameter(Mandatory=$true)]
    [string]$policyName,

    [Parameter(Mandatory=$true)]
    [String[]]$dnsNames,

    [Parameter()]
    [switch]$test = $false
)

$ErrorActionPreference = "Stop"

if ($apiKey -eq "")
{
    $apiKey = $env:ENCLAVE_API_KEY
}

if ($apiKey -eq "")
{
    Write-Error "No API key provided; either specify the 'apiKey' argument, or set the ENCLAVE_API_KEY environment variable."
    return;
}

# Attach our api key to each request.
$headers = @{Authorization = "Bearer $apiKey"}
$contentType = "application/json";

$response = Invoke-RestMethod -ContentType $contentType -Method Get -Uri "https://api.enclave.io/org/$orgId/policies?search=$policyName" -Headers $headers;

if ($response.total -eq 0)
{
    Write-Error "No policies found with name $policyName."
    return;
}
elseif ($response.total -gt 1)
{
    Write-Error "Multiple policies found with name $policyName; please provide a more specific name."
    return;
}

$policyId = $response.items[0].id;

Write-Host "Found policy $policyName with id $policyId."

# Get all IPv4 addresses for all provided DNS names:
$dnsAddresses = @();

foreach ($dnsName in $dnsNames)
{
    "Querying DNS for $dnsName..."
    try {
        $dnsAddresses += Resolve-DnsName $dnsName A | 
            Select-Object -ExpandProperty IPAddress | 
            ForEach-Object {@{
                ipRange = "$_"
                description = "$dnsName" 
            }}
    }
    catch {
        <#Do this if a terminating exception happens#>
        Write-Host "Failed to resolve DNS name $dnsName; continuing : $_"
    }
}

if ($dnsAddresses.Count -eq 0)
{
    Write-Error "No DNS addresses found for any of the provided DNS names."
    return;
}

$policyPatch = @{
    "gatewayAllowedIpRanges" = $dnsAddresses
} | ConvertTo-Json

if ($test)
{
    Write-Host "Test mode enabled; not updating policy."
    Write-Host "Would have updated policy $policyId with the following patch:"
    Write-Host $policyPatch
}
else
{
   Invoke-RestMethod -ContentType $contentType -Method Patch -Uri "https://api.enclave.io/org/$orgId/policies/$policyId" -Headers $headers -Body $policyPatch

   Write-Host "Updated policy with $($dnsAddresses.Count) IP addresses."
}

Usage

Preview the changes without modifying the policy:

.\gateway-policy-by-dns.ps1 -orgId 7G2AS `
                             -apiKey $env:ENCLAVE_API_KEY `
                             -policyName "ITGlue for Users" `
                             -dnsNames trantor.eu.itglue.com, `
                                       itglue-cdn-prod-itglue.com `
                             -test

Once you're happy with the output, remove the -test flag to apply the changes:

.\gateway-policy-by-dns.ps1 -orgId 7G2AS `
                             -apiKey $env:ENCLAVE_API_KEY `
                             -policyName "ITGlue for Users" `
                             -dnsNames trantor.eu.itglue.com, `
                                       itglue-cdn-prod-itglue.com

Scheduling

SaaS providers can change the IP addresses behind their DNS records at any time, so you should run this script on a recurring schedule to keep your gateway policy up to date. Windows Task Scheduler is the simplest option for a single site, but if you manage multiple organisations, consider running the script from your RMM platform or as an Azure Function on a timer trigger. Whichever approach you use, store your API key using the platform's secrets management rather than embedding it in the script or command line.