[HowTo] Sophos Firewall - Create and Maintain M365 Host Objects via Sophos Factory

Hi all,

Attached a Pipeline to generate M365 Host Objects in SFOS with Sophos Factory.

You need two Pipelines: One Child Pipeline and one Parent Pipeline: 

Get-O365WebserviceUpdates Pipeline: 

---
variables:
  - type: Credential
    name: firewallcreds
    key: firewallcreds
    value: FirewallCreds
    required: false
    visible: true
    default: false
    allowed_types:
      - username_password
  - type: String
    name: firewallhostname
    key: firewallhostname
    value: saleseng.de
    required: false
    visible: true
    default: false
steps:
  - id: GetO365
    name: GetO365
    type: powershell_script
    depends:
      - powershell_install1
    properties:
      content: |-
        <# Get-O365WebServiceUpdates.ps1
        From https://aka.ms/ipurlws
        v1.1 8/6/2019

        DESCRIPTION
        This script calls the REST API of the Office 365 IP and URL Web Service (Worldwide instance)
        and checks to see if there has been a new update since the version stored in an existing
        $Env:TEMP\O365_endpoints_latestversion.txt file in your user directory's temp folder
        (usually C:\Users\<username>\AppData\Local\Temp).
        If the file doesn't exist, or the latest version is newer than the current version in the
        file, the script returns IPs and/or URLs that have been changed, added or removed in the latest
        update and writes the new version and data to the output file $Env:TEMP\O365_endpoints_data.txt.

        USAGE
        Run as a scheduled task every 60 minutes.

        PARAMETERS
        n/a

        PREREQUISITES
        PS script execution policy: Bypass
        PowerShell 3.0 or later
        Does not require elevation
        #>

        #Requires -Version 3.0

        # web service root URL
        $ws = "https://endpoints.office.com"
        # path where output files will be stored
        $versionpath = $Env:TEMP + "\O365_endpoints_latestversion.txt"
        $datapath = $Env:TEMP + "\O365_endpoints_data.txt"

        # fetch client ID and version if version file exists; otherwise create new file and client ID
        if (Test-Path $versionpath) {
            $content = Get-Content $versionpath
            $clientRequestId = $content[0]
            $lastVersion = $content[1]
        #    Write-Output ("Version file exists! Current version: " + $lastVersion)
        }
        else {
        #    Write-Output ("First run! Creating version file at " + $versionpath + ".")
            $clientRequestId = [GUID]::NewGuid().Guid
            $lastVersion = "0000000000"
            @($clientRequestId, $lastVersion) | Out-File $versionpath
        }

        # call version method to check the latest version, and pull new data if version number is different
        $version = Invoke-RestMethod -Uri ($ws + "/version/Worldwide?clientRequestId=" + $clientRequestId)
        if ($version.latest -gt $lastVersion) {
        #    Write-Host "New version of Office 365 worldwide commercial service instance endpoints detected"
            # write the new version number to the version file
            @($clientRequestId, $version.latest) | Out-File $versionpath
            # invoke endpoints method to get the new data
            $endpointSets = Invoke-RestMethod -Uri ($ws + "/endpoints/Worldwide?clientRequestId=" + $clientRequestId)
            # filter results for Allow and Optimize endpoints, and transform these into custom objects with port and category
            # URL results
            $flatUrls = $endpointSets | ForEach-Object {
                $endpointSet = $_
                $urls = $(if ($endpointSet.urls.Count -gt 0) { $endpointSet.urls } else { @() })
                $urlCustomObjects = @()
                if ($endpointSet.category -in ("Allow", "Optimize")) {
                    $urlCustomObjects = $urls | ForEach-Object {
                        [PSCustomObject]@{
                            category = $endpointSet.category;
                            url      = $_;
                            tcpPorts = $endpointSet.tcpPorts;
                            udpPorts = $endpointSet.udpPorts;
                        }
                    }
                }
                $urlCustomObjects
            }
            # IPv4 results
            $flatIp4s = $endpointSets | ForEach-Object {
                $endpointSet = $_
                $ips = $(if ($endpointSet.ips.Count -gt 0) { $endpointSet.ips } else { @() })
                # IPv4 strings contain dots
                $ip4s = $ips | Where-Object { $_ -like '*.*' }
                $ip4CustomObjects = @()
                if ($endpointSet.category -in ("Allow", "Optimize")) {
                    $ip4CustomObjects = $ip4s | ForEach-Object {
                        [PSCustomObject]@{
                            category = $endpointSet.category;
                            ip = $_;
                            tcpPorts = $endpointSet.tcpPorts;
                            udpPorts = $endpointSet.udpPorts;
                        }
                    }
                }
                $ip4CustomObjects
            }
            # IPv6 results
            $flatIp6s = $endpointSets | ForEach-Object {
                $endpointSet = $_
                $ips = $(if ($endpointSet.ips.Count -gt 0) { $endpointSet.ips } else { @() })
                # IPv6 strings contain colons
                $ip6s = $ips | Where-Object { $_ -like '*:*' }
                $ip6CustomObjects = @()
                if ($endpointSet.category -in ("Optimize")) {
                    $ip6CustomObjects = $ip6s | ForEach-Object {
                        [PSCustomObject]@{
                            category = $endpointSet.category;
                            ip = $_;
                            tcpPorts = $endpointSet.tcpPorts;
                            udpPorts = $endpointSet.udpPorts;
                        }
                    }
                }
                $ip6CustomObjects
            }

            # write output to screen
        #    Write-Output ("Client Request ID: " + $clientRequestId)
        #    Write-Output ("Last Version: " + $lastVersion)
        #    Write-Output ("New Version: " + $version.latest)
        #   Write-Output ""
        #  Write-Output "IPv4 Firewall IP Address Ranges"
            ($flatIp4s.ip | Sort-Object -Unique) -join "," | Out-String
         #   Write-Output "IPv6 Firewall IP Address Ranges"
         #   ($flatIp6s.ip | Sort-Object -Unique) -join "," | Out-String
         #   Write-Output "URLs for Proxy Server"
         #   ($flatUrls.url | Sort-Object -Unique) -join "," | Out-String
         #   Write-Output ("IP and URL data written to " + $datapath)

            # write output to data file
         #   Write-Output "Office 365 IP and UL Web Service data" | Out-File $datapath
         #   Write-Output "Worldwide instance" | Out-File $datapath -Append
         #  Write-Output "" | Out-File $datapath -Append
         #   Write-Output ("Version: " + $version.latest) | Out-File $datapath -Append
         #   Write-Output "" | Out-File $datapath -Append
         #   Write-Output "IPv4 Firewall IP Address Ranges" | Out-File $datapath -Append
         #   ($flatIp4s.ip | Sort-Object -Unique) -join "," | Out-File $datapath -Append
         #   Write-Output "" | Out-File $datapath -Append
         #   Write-Output "IPv6 Firewall IP Address Ranges" | Out-File $datapath -Append
         #   ($flatIp6s.ip | Sort-Object -Unique) -join "," | Out-File $datapath -Append
         #   Write-Output "" | Out-File $datapath -Append
         #  Write-Output "URLs for Proxy Server" | Out-File $datapath -Append
         #   ($flatUrls.url | Sort-Object -Unique) -join "," | Out-File $datapath -Append
        }
        else {
            Write-Host "Office 365 worldwide commercial service instance endpoints are up-to-date."
        }
  - id: powershell_install1
    name: Install PowerShell
    type: powershell_install
    depends: []
    properties:
      version: latest
  - id: ips
    name: Create Array
    type: set_variables
    depends:
      - GetO365
    properties:
      vars:
        - key: ips
          value: '{|steps.GetO365.result.stdout | split('','')|}'
  - id: p1
    name: O365 Builder + Upload
    type: pipeline
    depends:
      - ips
    properties:
      pipeline_id: 65095199c75cbe2045b641a5
      pipeline_revision_id: latest
      variables:
        ips: '{|loop.item|}'
        index: '{|loop.index|}'
        firewallcreds: '{|vars.firewallcreds|}'
        firewallhostname: '{|vars.firewallhostname|}'
        subnetarray:
          - 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
    each: '{|vars.ips|}'
outputs:
  - key: ips
    value: '{|1|}'
layout:
  elements:
    - id: GetO365
      position:
        x: -155
        'y': -75
      links:
        - sourceId: powershell_install1
          sourcePort: bottom
          targetPort: top
          vertices: []
    - id: powershell_install1
      position:
        x: -155
        'y': -160
      links: []
    - id: ips
      position:
        x: -155
        'y': 10
      links:
        - sourceId: GetO365
          sourcePort: bottom
          targetPort: top
          vertices: []
    - id: p1
      position:
        x: -155
        'y': 100
      links:
        - sourceId: ips
          sourcePort: bottom
          targetPort: top
          vertices: []

O365 Builder Pipeline:

---
variables:
  - type: String
    name: ips
    key: ips
    required: false
    visible: true
    default: false
  - type: StringArray
    name: subnetarray
    key: subnetarray
    value:
      - 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
    required: false
    visible: false
    default: true
  - type: Number
    name: index
    key: index
    required: false
    visible: true
    default: false
  - type: Credential
    name: firewallcreds
    key: firewallcreds
    required: true
    visible: true
    default: false
    allowed_types:
      - username_password
  - type: String
    name: firewallhostname
    key: firewallhostname
    required: false
    visible: true
    default: false
steps:
  - id: Split
    name: split
    type: set_variables
    depends: []
    properties:
      vars:
        - key: ip
          value: '{|vars.ips | split(''/'') | first|}'
        - key: tmp
          value: '{|vars.ips | split(''/'') | last|}'
        - key: number
          value: '{|vars.index |}'
        - key: subnet
          value: '{|vars.subnetarray[vars.tmp]|}'
  - id: p1
    name: Set IP Host
    type: pipeline
    depends:
      - Split
    properties:
      pipeline_id: 627ec8fd2038a018ef03de65
      pipeline_revision_id: 650a02feeccbfcd0be7f213b
      variables:
        credential: '{|vars.firewallcreds|}'
        hostname: '{|vars.firewallhostname|}'
        port: 4444
        name: '{|"M365_" + vars.number|}'
        ipFamily: IPv4
        hostType: Network
        ipAddress: '{|vars.ip|}'
        subnet: '{|vars.subnet|}'
        groups:
          - M365
outputs:
  - key: ip
    value: '{|vars.ip|}'
  - key: subnet
    value: '{|vars.subnet|}'
  - key: number
    value: '{|vars.number|}'
layout:
  elements:
    - id: Split
      position:
        x: -195
        'y': -60
      links: []
    - id: p1
      position:
        x: -195
        'y': 20
      links:
        - sourceId: Split
          sourcePort: bottom
          targetPort: top
          vertices: []

Create the Pipeline and use the Editor to copy/paste the content in your Pipeline.
Use the same names for your Pipelines like i did. 

What you have to do: You have to enter your firewall IP and your Firewall Creds to Factory in the "Get-O365Webservices" Pipeline.

You can also generate a Job, which runs automatically each Day with different Creds/Hostnames, if you want. 

Talking about the Pipelines in Detail: 

Factory installs Powershell, uses the Microsoft Powershell Script to fetch the IP Addresses. Converts the output to an Array and Builds per IP an own API Call for the Firewall. 



Change title.
[bearbeitet von: LuCar Toni um 9:49 AM (GMT -7) am 22 Mar 2024]
Parents Reply Children
No Data