Contents

Anonymous IP address involving Apple iCloud Private Relay

Since a few weeks I recognized an uptick in Entra ID Protection alerts regarding “Anonymous IP address” detections. Normally this is a high-fidelity indicator that someone is using a Tor browser or some other method to cover their tracks. While this behavior is totally fine in a private setting, in enterprise IT the use of such anonymizers is not considered baseline behavior.

While analyzing the related alerts for common patterns I stumbled upon the IP address information. Most of those sign-ins are from IPv6 addresses that are hosted in e.g. Cloudflare datacenters.

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/SentinelIPEntity.png
Microsoft Sentinel IP address insights are already helpful...

While the IP address information in Sentinel is not wrong, using a third-party source for IP address enrichment the culprit of those alerts was found fast. Apple iCloud Private Relay.

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/DetailedIPInformation.png
...but sometime third party data sources are even better.

If you don’t know what the Apple iCloud Private Relay service is the About website of Apple gives a good description.

iCloud Private Relay is designed to protect your privacy by ensuring that when you browse the web in Safari, no single party - not even Apple - can see both who you are and what sites you’re visiting.

So basically, the Apple iCloud Private Relay is a VPN solution that anonymizes your original IP address from the service you are using. In this case Entra ID. The alert therefore is not wrong.

As many Apple device users are also iCloud+ subscribers the features is enabled on more and more Apple devices. While this is a manual process it seems that either Apple is nudging the users to enable it or, as I see users from Germany, they are just a bit more privacy focused and enable it on purpose.

As a company you now have to decide if you consider the use of such an “official” and more widespread VPN solution from Apple or Google (VPN by Google One) a security risk and you force the users to disable it, or if you accept the risk (pun intended) and “ignore” the alerts related to the IP address spaces.

Automated incident handling

Identify if the IP address is part of Apples iCloud Private relay in KQL

If you decide for yourself that this behavior is acceptable it’s time for some automation. You don’t want your SOC analysts manually doing the lookup themselves but handle such incidents using a SOAR solution.

First you need a reliable source of IP address ranges that are part of the Apple iCloud Private Relay. Luckily Apple themselves offers a CSV with all IP address ranges.

A few weeks ago, for some reason, it was not possible to directly use the CSV file in a KQL query. The server was not returning the file correctly and the query failed. That’s why I build a small GitHub workflow that pulls the data, add the information about the IP address type and can be used within Log Analytics / Microsoft Sentinel.

In the meantime something seems to have changed and the CSV can be used directly, but I didn’t bother to change my query again.

This query can check if the IP address provided is part of the Apple IP address ranges and based on this result you can now decide to close the incident automatically.

let AppleiCloudPrivateRelayRanges = externaldata(IPRange: string, Country: string, LanguageCode: string, City: string, AddressFamily: string) [
    @"https://raw.githubusercontent.com/f-bader/AzSentinelQueries/master/ExternalData/iCloudPrivateRelayIPRanges.csv"]
    with(format="csv", ignoreFirstRecord=true)
    | summarize IPRange=make_set(IPRange) by AddressFamily;
let AppleiCloudPrivateRelayRangesIPv4 = toscalar(AppleiCloudPrivateRelayRanges
    | where AddressFamily == "InterNetwork"
    | project IPRange);
let AppleiCloudPrivateRelayRangesIPv6 = toscalar(AppleiCloudPrivateRelayRanges
    | where AddressFamily == "InterNetworkV6"
    | project IPRange);
print "2a09:bac3:2a10:2c8::47:2e8"
| project-rename IPAddress = print_0
| extend IsInAppleiCloudv4Range = ipv4_is_in_any_range(IPAddress, AppleiCloudPrivateRelayRangesIPv4)
| extend IsInAppleiCloudv6Range = ipv6_is_in_any_range(IPAddress, AppleiCloudPrivateRelayRangesIPv6)
| extend IsInAppleiCloudRange = coalesce(IsInAppleiCloudv4Range, IsInAppleiCloudv6Range)
| project-away IsInAppleiCloudv4Range, IsInAppleiCloudv6Range

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/SentinelQueryResults.png
For this IPv6 address the lookup was successful

Build a Logic App to close the incident

Armed with this query we can create a Logic App that will check if all the IP addresses in the incident are part of the Apple iCloud Private relay network, and if so close the incident as benign.

I will not go into the detailed explanation on how to create a Logic App for Sentinel, but I provide the ready to use Logic App as part of my GitHub repository.

Have a look at the basic steps that are needed to implement such a solution.

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/LogicApp.png
Logic App overview

As you can see at first I initialize a variable called “CloseIncident” which will be set to true . This is because we want a logic where, if there is at least one IP address that does not belong to the Apple network, the incident should not be closed. Therefor if I would set this to true every time a IP address is found in those network ranges, a single IP address with the result false could be overwritten.

The second step is a precaution to only run when the incident title matches the use case.

Then all IP entities are extracted from the incident body and for each of those IP addresses a KQL query is run against the Sentinel Log Analytics workspace, using a system managed identity.

The response is parsed and then it will check if the length of the rows is equal to 0. If this is the case, this means that the IP address is NOT part of the IP ranges in question and the incident should NOT be closed automatically. The variable CloseIncident is then set to false .

Otherwise, there is no change to the variable.

At the end, if all IP addresses are checked, depending of the CloseIncident variable the incident will be either closed (who guessed) or the logic app will just add a comment. That way it’s clearer to the analyst that there was an automation playbook running and they can use the result as a starting point in the investigation.

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/IncidentAutoClosed.png
Auto closed incident with closure reason

/en/anonymous-ip-address-involving-apple-icloud-private-relay/images/IncidentComment.png
The comment if the logic app does not find the IP address in the network range

Conclusion

As you can see, investing in automation can help you SOC to be more productive and known false or benign positives, which can be identified with near to 100% confidence, can be fully automated. That way the sea of alerts can be reduced, and your SOC analysts can invest more time in other investigations.

Of course, you always must consider edge cases and make sure you take those into account. You don’t want to auto close your incidents based on faulty logic and risk that you miss important indicators of an attack.

I hope you enjoyed this excursion into SOAR automation. Let me know if you would like a more detailed blog post on how to create reusable Logic Apps. I already published my base template.