Sophos Firewall: PowerShell Script Library for migrating Sophos UTM to Sophos Firewall

Disclaimer: This information is provided as-is for the benefit of the Community. Please contact Sophos Professional Services if you require assistance with your specific environment.


Overview

This Recommended read describes ways to migrate Sophos UTM Configurations parts to Sophos Firewall, with UTM API and Import/Export Features.

This will also include Powershell Scripts to migrate some Features and options. 

Migration Desk

This is free to all Partners (and subsequently customers) that will assist in planning, executing, and verifying migrations of your existing firewall or Sophos UTM to Sophos Firewall migrations.

The following scripts follow an easy approach: This will download the configuration via JSON UTM API and convert this content to an XML File. The XML File is usable in SFOS for more information about the approach.

Sophos UTM offers a full API and a "Swagger" tool for the entire configuration.

Accessing API

You can access the API of Sophos UTM by using https://IP:4444/api 

The Swagger UI offers you the Schema UTM uses for every feature.

For example, Network Host Objects

It’ll show you the CURL request and Token you need to do to GET the data. You’ll also see the format in this code. 

We can now use the data we get via API and convert it to XML Data. We need to map the matching points of UTM to SFOS.


In the example below, We map the data of the UTM "name" to the SFOS name, and we'll map the IP address to the IP address. Then, add the rest of the XML code, which is static. The approach of this migration is always the same: fetch the data, convert it to XML, and save it. 

Kindly replace the IP and the Authorization Token in the Script and run it via Powershell. 

Convert Host Objects to XML

#Code to accept untrusted UTM connections. Not needed, if you use a trusted CA for the UTM webadmin. 

add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem) {
            return true;
        }
 }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" -Position 0



# Define the URL for the API // Replace the IP with your UTM IP. 
$url = "https://172.25.105.16:4444/api/objects/network/host/"

# Define the headers for the request // Replace the Authorization Code with your UTM Code. See Swagger. 
$headers = @{
    Accept = "application/json"
    Authorization = "Basic YWRtaW46U29waG9zLjE="
}

# Send a GET request to the API and store the result in a variable
$jsonResult = Invoke-RestMethod -Uri $url -Headers $headers -Method Get

# Convert the JSON data to XML
$xmlResult = [xml]@"
<?xml version="1.0" encoding="UTF-8"?>
<Configuration APIVersion="1905.1" IPS_CAT_VER="1">
$(
    foreach ($item in $jsonResult) {
        "  <IPHost>"
        "    <Name>$($item.name)</Name>"
        "    <IPFamily>IPv4</IPFamily>"
        "    <HostType>IP</HostType>"
        "    <IPAddress>$($item.address)</IPAddress>"
        "  </IPHost>"
    }
)
</Configuration>
"@

# Save the XML data to a file in the same directory as the script
$filePath = Join-Path -Path (Split-Path -Path $MyInvocation.MyCommand.Path -Parent) -ChildPath "Entities.xml"
$xmlResult.Save($filePath)
=

Convert Network Objects to XML 

add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem) {
            return true;
        }
 }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" -Position 0
# Define the URL for the API // Replace the IP with your UTM IP. 
$url = "https://172.25.105.16:4444/api/objects/network/network/"

# Define the headers for the request // Replace the Authorization Code with your UTM Code. See Swagger. 
$headers = @{
    Accept = "application/json"
    Authorization = "Basic YWRtaW46U29waG9zLjE="
}

# Send a GET request to the API and store the result in a variable
$jsonResult = Invoke-RestMethod -Uri $url -Headers $headers -Method Get

# Define the subnet mask mapping
$subnetMasks = @("0.0.0.0","128.0.0.0","192.0.0.0","224.0.0.0","240.0.0.0","248.0.0.0","252.0.0.0","254.0.0.0",
                 "255.0.0.0","255.128.0.0","255.192.0.0","255.224.0.0","255.240.0.0","255.248.0.0","255.252.0.0","255.254.0.0",
                 "255.255.0.0","255.255.128.0","255.255.192.0","255.255.224.0","255.255.240.0","255.255.248.0","255.255.252.0","255.255.254.0",
                 "255.255.255.0","255.255.255.128","255.255.255.192","255.255.255.224","255.255.255.240","255.255.255.248","255.255.255.252","255.255.255.254","255.255.255.255")

# Convert the JSON data to XML
$xmlResult = [xml]@"
<?xml version="1.0" encoding="UTF-8"?>
<Configuration APIVersion="1905.1" IPS_CAT_VER="1">
$(
    foreach ($item in $jsonResult) {
        "  <IPHost>"
        "    <Name>$($item.name)</Name>"
        "    <IPFamily>IPv4</IPFamily>"
        "    <HostType>Network</HostType>"
        "    <IPAddress>$($item.address)</IPAddress>"
		"	<Subnet>$($subnetMasks[$item.netmask])</Subnet>"
        "  </IPHost>"
 }
)
</Configuration>
"@

# Save the XML data to a file in the same directory as the script
$filePath = Join-Path -Path (Split-Path -Path $MyInvocation.MyCommand.Path -Parent) -ChildPath "Entities.xml"
$xmlResult.Save($filePath)

Convert REDs from UTM to SFOS

Use this code with Caution. RED can only be deployed with one Firewall (UTM or SFOS). If you register the RED from UTM to SFOS, iRED will begin to restart. 
This code is very static and won’t migrate complex RED deployments like UMTS, Transparent / Split, or other scenarios. It won’t migrate DHCP Servers but will keep the IP Addresses of the REDs. 

add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
    public bool CheckValidationResult(
        ServicePoint srvPoint, X509Certificate certificate,
        WebRequest request, int certificateProblem) {
            return true;
        }
 }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" -Position 0
# Define the URL for the API // Replace the IP with your UTM IP. 
$url = "https://172.25.105.16:4444/api/objects/itfhw/red_server/"
$url2 = "https://172.25.105.16:4444/api/objects/interface/ethernet/"
$url3 = "https://172.25.105.16:4444/api/objects/itfparams/primary/"

# Define the headers for the request // Replace the Authorization Code with your UTM Code. See Swagger. 
$headers = @{
    Accept = "application/json"
    Authorization = "Basic YWRtaW46U29waG9zLjE="
}

# Send a GET request to the API and store the result in a variable
$jsonResult = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
$jsonEthernet = Invoke-RestMethod -Uri $url2 -Headers $headers -Method Get
$jsonparams = Invoke-RestMethod -Uri $url3 -Headers $headers -Method Get

#SubnetMasks
$subnetMasks = @("0.0.0.0","128.0.0.0","192.0.0.0","224.0.0.0","240.0.0.0","248.0.0.0","252.0.0.0","254.0.0.0",
                 "255.0.0.0","255.128.0.0","255.192.0.0","255.224.0.0","255.240.0.0","255.248.0.0","255.252.0.0","255.254.0.0",
                 "255.255.0.0","255.255.128.0","255.255.192.0","255.255.224.0","255.255.240.0","255.255.248.0","255.255.252.0","255.255.254.0",
                 "255.255.255.0","255.255.255.128","255.255.255.192","255.255.255.224","255.255.255.240","255.255.255.248","255.255.255.252","255.255.255.254","255.255.255.255")

# Convert the JSON data to XML
$xmlResult = [xml]@"
<?xml version="1.0" encoding="UTF-8"?>
<Configuration APIVersion="1905.1" IPS_CAT_VER="1">
$(
    foreach ($item in $jsonResult) {
	$itfmatch =  $jsonEthernet | Where-Object {$_.itfhw -eq $item._ref}
	$ip = $jsonparams | Where-Object {$_._ref -eq $itfmatch.primary_address}
	"		<REDDevice transactionid="""">"
	"		<BranchName>$($item.name)</BranchName>"
	"		<Device>$($item.type)</Device>"
	"		<REDDeviceID>$($item.red_id)</REDDeviceID>"
	"		<TunnelID>Automatic</TunnelID>"
	"		<REDMTU>1500</REDMTU>"
	"		<Description>$($item.comment)</Description>"
	"		<NetworkSetting>"
	"			<Zone>LAN</Zone>"
    "           <DhcpStatus>Disable</DhcpStatus>"
	"			<TunnelCompression>Disable</TunnelCompression>"
	"			<OperationMode>Standard</OperationMode>"
	"			<IPAddress>$($ip.address)</IPAddress>"
	"			<NetMask>$($subnetMasks[$ip.netmask])</NetMask>"
	"			<MACFilter>"
	"		<FilterType>None</FilterType>"
	"			</MACFilter>"
	"		</NetworkSetting>"
	"		<Authorized>1</Authorized>"
	"		<UnlockCode>$($item.unlock_code)</UnlockCode>"
	"		<UTMHostName>$($item.hub_hostname)</UTMHostName>"
	"		<SecondUTMHostName>$($item.hub2_hostname)</SecondUTMHostName>"
	"		<Use2ndIPHostNameFor>Failover</Use2ndIPHostNameFor>"
	"		<DeploymentMode>AutoDeployment</DeploymentMode>"
	"		<UplinkSettings>"
	"			<Uplink>"
	"			<Connection>DHCP</Connection>"
	"			</Uplink>"
	"			<UMTS3GFailover>Disable</UMTS3GFailover>"
	"		</UplinkSettings>"
	"		</REDDevice>"
 }
)
</Configuration>
"@

# Save the XML data to a file in the same directory as the script
$filePath = Join-Path -Path (Split-Path -Path $MyInvocation.MyCommand.Path -Parent) -ChildPath "Entities.xml"
$xmlResult.Save($filePath)

Important Note: The code will generate XML Files for SFOSv19.5. If you want to use the XML in an older version of SFOS, adjust the following line: 
<Configuration APIVersion="1905.1" IPS_CAT_VER="1">     

Feel free to contribute more code for migration scenarios. We’ll provide more code in the future. 




Revamped RR Corrected Grammar & Font Size Added Horizontal Lines
[edited by: Erick Jan at 11:56 AM (GMT -7) on 28 Sep 2023]
  • Just to highlight the Code in #3. This code will not migrate everything. So be careful with this code. 

    __________________________________________________________________________________________________________________

  • __________________________________________________________________________________________________________________

  • Is there still a script planned for the service definitions and firewall rules?

    Thx!

  • The tool above will migrate services.

    Firewall Rules often times does not reflect a need to migrate, as they are different approaches in SFOS vs UTM. 

    And firewall rules have a big problem in the migration process: You need for Firewall Rules often times services, Network Object, IP objects etc. So you need to figure out how to migrate those objects upfront. 

    __________________________________________________________________________________________________________________

  • I am about to build the IPsec Site to Site Tunnel migration part, but bumping into the problem of "local / remote Subnet" section. Therefore i am about to release the Powershell script without the migration of Local / remote Subnet or i can migrate only "the names" and the admin has to migrate the objects before. 

    As UTM and SFOS uses only the names of the objects (Network 1), i can migrate the names, but the names have to exists before the migration. 

    __________________________________________________________________________________________________________________

  • LuCar, with this code, and the statement "If you register the RED from UTM to SFOS, iRED will start to reboot.", do you mean it will restart the RED and then join the XG/XGS, without losing the configuration it has, or, do you mean it will go into a reboot loop and lose the configuration it has? 

    We're presently in a scenario where we are migrating to SFOS and have REDs with static IP only, and no access to DHCP service, meaning this would be a saviour!

  • This is a tricky question: You should try it with one RED and check, what happens. But this script will not migrate the static configuration - You would have to adjust it. 

    __________________________________________________________________________________________________________________

  • I think my two co-workers in the remote office that I already had to have take the RED home when we tried this, would "k1ll" me if I experimented with them again. :)  We could handle doing the configuration on the XGS again, I just need to know that the RED won't reset and default back to DHCP.  My original thought was to turn off (not delete) the connection in the UTM and then add it to the XGS with the current unlock code.  However, having downloaded the manual config file for the RED on both an XGS and a UTM, they are definitely different, but not much different.  The one big mystery that is left, if my plan worked, is, what happens firmware wise, as I believe the addition onto a XGS triggers an update...

  • So if you upload a RED + Unlockcode to a product (UTM/SFOS) it will reach out to the Provisioning server and overwrite the config there. 

    If you have a offline deployment, the RED essentially does not care. 

    __________________________________________________________________________________________________________________

  • *dont care, unless you delete the RED from the original Firewall, as the red will fallback and ask the provisioning server. 

    __________________________________________________________________________________________________________________