This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Office365 deployment best practice

We are in the process of migrating to Office365. As part of the process, the networked is evaluated and the first recommendation by Microsoft is to remove any proxies from the path between the user and Office365. The problem with this is that MS has a ton of IP Address ranges and URLs.

The primary guidelines are:

  1. Use a proxy PAC files to send all the MS URLs direct.
  2. Create policies on the firewall to allow all IP ranges and URLs

https://support.office.com/en-us/article/managing-office-365-endpoints-99cab9d4-ef59-4207-9f2b-3728eb46bf9a?ui=en-US&rs=en-US&ad=US

Really good overview of their philosophy from Ignite:

https://www.youtube.com/watch?v=19a8s90HboQ&feature=youtu.be

Here is the entire IP/URL List in XML format: https://support.content.office.net/en-us/static/O365IPAddresses.xml

The problem I see is managing the list of IP Addresses and URLs. The list is long and changes somewhat frequently, so it's not just a matter of doing it once, you have to maintain it. As far as I know, there is no Network object in the UTM that let's you drop a list of subnets. That wouldn't be bad. But it appears that each subnet has to be created as a network definition and them maybe added to a group. But some places in Sophos do not accept groups, so then each subnet would have to be dragged one at a time in the interface. Again tedious to implement and more tedious to maintain.

I could use the API, but that would have to be run against each UTM. This will take a bit of work to implement, but may be the best solution long term.

Has anyone discovered an easy solution to keeping this type of thing up to date?



This thread was automatically locked due to age.
Parents
  • Next question, after downloading the MS IP addresses, the total count is 659 subnets. Can the Sophos handle that many network objects? Sometimes it struggles enumerating network definitions and I only have 450 now.

  • Done. Updated all three UTM devices using PowerShell and the Sophos API. I am relatively new to PowerShell, so this was quite an exercise, I hope this might help others map the Sophos API examples to PowerShell commands.

    # 2018-03-17 TJB
    <#
    This script downloads the xml IP list from Microsoft, adds/removes Sophos Network Objects and creates/modifies a Group of Networks.
    Requirements:
        Sophos API Enabled
        Local Sophos account with admin privelages configures with an API Key
    Input Parameter: $UTM
        Script expects a hashtable to be passed in the following format:
            @{UTM = 'SophosDeviceName';
              URL = 'SophosDeviceName.company.com:4444/api;
              KEY = 'apiKeyFromSophosDevice';
              DBG = $true/$false - activates pause in script}
    #>
    Param([parameter(Mandatory=$true)]$utm)
    $comment = 'Microsoft IPv4 | ' + (Get-Date).ToString("yyyy-MM-dd") + ' PS1'
    $apiURL = $utm.URL
    $networkURI = $apiURL + '/objects/network/network/'
    $groupURI = $apiURL + '/objects/network/group/'
    $resultCSV = '\\server\folder\resultList.csv'
    $msGroup = @()    #Sophos Network Group that will contain all of the network object created
    $utmNetList = @() #All Networks retrieved from the UTM
    $msNetList = @()  #UTM Networks filtered for MS-
    $ipList = @()     #IP Addresses downloaded from Microsoft XML
    $ipNetList = @()  #IP Addresses parsed into Network format
    $resultList = @() #Dispositon of networks for notification
    $emailHeader = @{smtpserver = 'mail';
                     subject = 'Microosft IPv4 Address Update for ' + $utm.UTM;
                     to = 'user1@company.com';
                     from = 'user2@company.com'}
                    
    #Must have corresponding account configured with token on UTM
    $token = $utm.KEY
    $tokenBase64 = [Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes("token:" + $token))
    #Common headers required by Sophos API
    $headers = @{}
    $headers.add("Authorization",'Basic ' + $tokenBase64)
    $headers.add("Content-Type", "application/json")
    $headers.add("Accept", "application/json")
    #Sets the TLS level to match Sophos
    $AllProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
    [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols
    #Retrieve the existing list of MS subnets from Sophos
    $utmNetList = Invoke-RestMethod -Uri $networkURI -Method Get -Headers $headers
    $msNetList = $utmNetList | where {$_.name -like 'MS-*/*' -and $_.comment -like 'Microsoft*PS1'}

    # Jordan's code to retrieve and parse the Microsoft XML IP List
    [xml]$xml = (New-Object System.Net.WebClient).DownloadString("support.content.office.net/.../O365IPAddresses.xml");
    $xml.products.product | % {
        $_.addresslist | ? {$_.type -like 'IPv4' } | Select -Expand address -EA SilentlyContinue | Sort -Unique | % {
            $ipList += $_
            }
    }
    $ipList = $ipList | sort -Unique

    #Format IP List into Network hashtable
    foreach ($ip in $ipList)
    {
        $net = $ip.split("/")
        $ipAddress = $net[0]
        $netmask = $net[1]
        $name = 'MS-' + $ip
        $subnet = @{address = $ipAddress;
                    address6 = "";
                    comment = $comment;
                    interface = "";
                    name = $name;
                    netmask = $netmask;
                    netmask6 = "0";
                    resolved = $true;
                    resolved6 = $false}
        $subnet = $subnet | ConvertTo-Json | ConvertFrom-Json
        $ipNetList += $subnet
    }

    # Add new subnets to Sophos UTM
    foreach ($ipNet in $ipNetList)
    {
        $action = ""
        $ref = ""
        $result = @()
        if ($msNetList -match $ipNet.name)
        {
            Write-Host $ipNet.name already exists
            $action = 'Exists'
            $ref = ($msNetList | where {$_.name -eq $ipNet.name})._ref
        }
        else
        {
            Write-Host Need to create network object $ipNet.name on Sophos UTM
            $result = Invoke-RestMethod -Uri $networkURI -Method Post -Headers $headers -Body (ConvertTo-Json $ipNet)
            if ($result.name -eq $ipNet.name)
            {
                Write-Host Subnet created successfully
                $action = 'Added'
                $ref = $result._ref
            }
            else
            {
                $action = 'AddFailed'
            }
        }
        $resultList += @{action = $action; network = $ipNet.name; _ref = $ref}
        #if ($utm.DBG){pause}
    }

    # Old Subnets to remove from Sophos UTM
    foreach ($msNet in $msNetList)
    {
        $action = ""
        if ($ipNetList -match $msNet.name)
        {
            Write-Host $msNet.name is still valid
        }
        else
        {
            Write-Host Need to remove network object $msNet.name from Sophos UTM
            $action = "Remove"
            $resultList += @{action = $action; network = $msNet.name; _ref = $msNet._ref}
        }
        #if ($utm.DBG){pause}
    }

    #Update "Microsoft IPv4 Subnets" group if any subnets added or removed
    if (($resultList | where {$_.action -eq "Added"}).count -gt 0 -or ($resultList | where {$_.action -eq "Remove"}).count -gt 0)
    {
        $result = @()
        $msGrpMembers = @()
        $grpBody = @{}
        $networkGroups = Invoke-RestMethod -Uri $groupURI -Method Get -Headers $headers
        $msGroup = $networkGroups | where {$_.name -eq 'Microsoft IPv4 Subnets'}
        if ($msGroup.name -ne 'Microsoft IPv4 Subnets')
        {
            $grpMethod = 'Post'
            $msGroupUri = $groupURI
        }
        else
        {
            $grpMethod = 'Patch'
            $msGroupUri = $groupURI + $msGroup._ref
        }
        foreach ($result in $resultList)
        {
            if ($result.action -ne 'Remove')
            {
                $msGrpMembers += $result._ref
            }
        }
        $grpBody = @{comment = $comment;
                     name = "Microsoft IPv4 Subnets";
                     members = $msGrpMembers}
        Invoke-RestMethod -Uri $msGroupUri -Method $grpMethod -Headers $headers -Body (ConvertTo-Json $grpBody)
        $resultList.ForEach({[PSCustomObject]$_}) | Export-Csv $resultCSV -Force -NoTypeInformation
        $emailHeader.Add('Body', 'Result file attached')
        $emailHeader.Add('Attachments', $resultCSV)
        #if($utm.DBG){pause}
    }
    else
    {
        $emailHeader.Add('Body','No IP address changes made this run')
    }
    #Remove unused subnets from Sophos UTM
    if (($resultList | where {$_.action -eq "Remove"}).count -gt 0)
    {
        $result = @()
        $msGrpMembers = @()
        $grpBody = @{}
        $headers.add("X-Restd-Err-Ack", "all")
        foreach ($result in $resultList)
        {
            if ($result.action -eq 'Remove')
            {
                Write-Host Deleting Network object $result.network
                $delNetURI = $networkURI + $result._ref
                Invoke-RestMethod -Uri $delNetURI -Method Delete -Headers $headers -Body (ConvertTo-Json $ipNet)
            }
        }
    }
    #Sends e-mail with list of ranges and action taken
    Send-MailMessage @emailHeader
  • I am calling the script above with this script. This script maintains the list of Sophos devices and they API Keys. Loops through the list calling other specified script. I plan to create a few other scripts to update other components and this way the API keys are maintained in a single script I can secure a bit more than usual.

    <#
    .SYNOPSIS
    2018-03-17 TJB - Calls scripts for set of defined UTM Devices
    .DESCRIPTION
    Contains the list of UTM devices and their API keys. Keep safe.
    .PARAMETER Script
    Full path to the powershell script to be run against the list of UTM devices. Script must accept hashtable variable.
    .PARAMETER debugPause
    Whether or not to pause between servers. Can be passed along to the called script.
    #>
    Param([parameter(Mandatory=$true)]$Script,
          [Bool]$debugPause = $false)
    $utmList = @(
        @{UTM = 'Sophos1';
          URL = 'sophos1.domain.com:4444/api';
          KEY = 'Sophos1RandomAPIKey';
          DBG = $debugPause},
        @{UTM = 'Sophos2';
          URL = 'sophos2.domain.com:4444/api';
          KEY = 'Sophos2RandomAPIKey';
          DBG = $debugPause},
        @{UTM = 'Sophos3';
          URL = 'sophos3.domain.com:4444/api';
          KEY = 'Sophos3RandomAPIKey';
          DBG = $debugPause})
    foreach ($utm in $utmList)
    {
        #Write-Host $utm.URL
        & $Script $utm
        if ($debugPause){pause}
    }
  • Thanks, Tim - this thread is a great contribution!  I'll prioritize this at the top of this forum with "forever" selected.

    Cheers - Bob

     
    Sophos UTM Community Moderator
    Sophos Certified Architect - UTM
    Sophos Certified Engineer - XG
    Gold Solution Partner since 2005
    MediaSoft, Inc. USA
Reply
  • Thanks, Tim - this thread is a great contribution!  I'll prioritize this at the top of this forum with "forever" selected.

    Cheers - Bob

     
    Sophos UTM Community Moderator
    Sophos Certified Architect - UTM
    Sophos Certified Engineer - XG
    Gold Solution Partner since 2005
    MediaSoft, Inc. USA
Children
No Data