General information about setting up an allow list for wp-login.php, /wp-admin, and xmlrpc.php can be found in the main
WordPress login and xmlrpc.php IIS restrictions article. With this article focused on the additional markup when using Cloudflare.
Cloudflare IP Ranges Allow List
In addition to the Cloudflare IP ranges, the ipSecurity attribute "enableProxyMode" needs to be set to true in order to obtain the original visitor IP, which is sent via an X-Forwarded-For header. Both updates would be made to the top level system.webServer element, outside of the location tags used for the wp-login.php, wp-admin, and xmlrpc.php allow lists.
Example
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<security>
<ipSecurity enableProxyMode="true">
<!--Cloudflare allow list-->
<add ipAddress="103.21.244.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="103.22.200.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="103.31.4.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="104.16.0.0" subnetMask="255.248.0.0" allowed="true" />
<add ipAddress="104.24.0.0" subnetMask="255.252.0.0" allowed="true" />
<add ipAddress="108.162.192.0" subnetMask="255.255.192.0" allowed="true" />
<add ipAddress="131.0.72.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="141.101.64.0" subnetMask="255.255.192.0" allowed="true" />
<add ipAddress="162.158.0.0" subnetMask="255.254.0.0" allowed="true" />
<add ipAddress="172.64.0.0" subnetMask="255.248.0.0" allowed="true" />
<add ipAddress="173.245.48.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="188.114.96.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="190.93.240.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="197.234.240.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="198.41.128.0" subnetMask="255.255.128.0" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
Example WordPress web.config with Permalinks
Completed web.config with sections added to restrict access to wp-login.php, /wp-admin and xmlrpc.php when routing traffic through Cloudflare. Requires updating the ipAddress for any site visitors that should have access to wp-login.php and /wp-admin.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<location path="wp-login.php">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<add ipAddress="xx.xx.xx.xx" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>
<location path="wp-admin">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<add ipAddress="xx.xx.xx.xx" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>
<location path="xmlrpc.php">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<!--Jetpack allow list-->
<add ipAddress="122.248.245.244" subnetMask="255.255.255.255" allowed="true" />
<add ipAddress="54.217.201.243" subnetMask="255.255.255.255" allowed="true" />
<add ipAddress="54.232.116.4" subnetMask="255.255.255.255" allowed="true" />
<add ipAddress="192.0.80.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="192.0.96.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="192.0.112.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="195.234.108.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="192.0.64.0" subnetMask="255.255.192.0" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>
<system.webServer>
<rewrite>
<rules>
<rule name="WordPress Rule" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
<security>
<ipSecurity enableProxyMode="true">
<!--Cloudflare allow list-->
<add ipAddress="103.21.244.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="103.22.200.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="103.31.4.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="104.16.0.0" subnetMask="255.248.0.0" allowed="true" />
<add ipAddress="104.24.0.0" subnetMask="255.252.0.0" allowed="true" />
<add ipAddress="108.162.192.0" subnetMask="255.255.192.0" allowed="true" />
<add ipAddress="131.0.72.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="141.101.64.0" subnetMask="255.255.192.0" allowed="true" />
<add ipAddress="162.158.0.0" subnetMask="255.254.0.0" allowed="true" />
<add ipAddress="172.64.0.0" subnetMask="255.248.0.0" allowed="true" />
<add ipAddress="173.245.48.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="188.114.96.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="190.93.240.0" subnetMask="255.255.240.0" allowed="true" />
<add ipAddress="197.234.240.0" subnetMask="255.255.252.0" allowed="true" />
<add ipAddress="198.41.128.0" subnetMask="255.255.128.0" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</configuration>