Recommended network policies
We recommend you add the following network policies to build an Internet and SaaS app security strategy for your organization.
For more information on building network policies, refer to Network policies.
Restrict access for users included in an identity provider (IdP) user group for risky users. This policy ensures your security team can restrict traffic for users of whom malicious or suspicious activity was detected.
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | not in list | Quarantined-Users-IPAllowlist | Or | Block |
SNI | not in list | Quarantined-Users-HostAllowlist | Or | |
SNI Domain | not in list | Quarantined-Users-DomainAllowlist | And | |
User Group Names | in | Quarantined Users |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "Quarantined-Users-NET-Restricted-Access", "description": "Restrict access for users included in an IdP user group for risky users", "precedence": 0, "enabled": true, "action": "block", "filters": [ "l4" ], "traffic": "not(net.dst.ip in $<IP_ALLOWLIST_UUID>) or not(net.sni.host in $<HOST_ALLOWLIST_UUID>) or not(any(net.sni.domains[*] in $<DOMAIN_ALLOWLIST_UUID>))", "identity": "any(identity.groups.name[*] in {\"Quarantined Users\"})"}'
resource "cloudflare_zero_trust_gateway_policy" "quarantined_users_net_restricted_access" { account_id = var.cloudflare_account_id name = "Quarantined-Users-NET-Restricted-Access" description = "Restrict access for users included in an IdP user group for risky users" precedence = 0 enabled = true action = "block" filters = ["l4"] traffic = "not(net.dst.ip in ${"$"}${cloudflare_zero_trust_list.ip_allowlist.id}) or not(net.sni.host in ${"$"}${cloudflare_zero_trust_list.host_allowlist.id}) or not(any(net.sni.domains[*] in ${"$"}${cloudflare_zero_trust_list.domain_allowlist.id}))" identity = "any(identity.groups.name[*] in {\"Quarantined Users\"})"}
Restrict access for devices where baseline posture checks have not passed. If posture checks are integrated with service providers such as Crowdstrike or Intune via the API, this policy dynamically blocks access for devices that do not meet predetermined security requirements.
Restrict access for users included in an identity provider (IdP) user group for risky users. This policy ensures your security team can restrict traffic for users of whom malicious or suspicious activity was detected.
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | not in list | Posture-Fail-IPAllowlist | Or | Block |
SNI | not in list | Posture-Fail-HostAllowlist | Or | |
SNI Domain | not in list | Posture-Fail-DomainAllowlist | And | |
Passed Device Posture Checks | not in | Windows 10 or higher (OS version) |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "Posture-Fail-NET-Restricted-Access", "description": "Restrict access for devices where baseline posture checks have not passed", "precedence": 0, "enabled": true, "action": "block", "filters": [ "l4" ], "traffic": "not(net.dst.ip in $<IP_ALLOWLIST_UUID>) or not(net.sni.host in $<HOST_ALLOWLIST_UUID>) or not(any(net.sni.domains[*] in $<DOMAIN_ALLOWLIST_UUID>))", "device_posture": "not(any(device_posture.checks.passed[*] in {\"<DEVICE_POSTURE_CHECK_UUID>\"}))"}'
resource "cloudflare_zero_trust_gateway_policy" "posture_fail_net_restricted_access" { account_id = var.cloudflare_account_id name = "Posture-Fail-NET-Restricted-Access" description = "Restrict access for devices where baseline posture checks have not passed" precedence = 0 enabled = true action = "block" filters = ["l4"] traffic = "not(net.dst.ip in ${"$"}${cloudflare_zero_trust_list.ip_allowlist.id}) or not(net.sni.host in ${"$"}${cloudflare_zero_trust_list.host_allowlist.id}) or not(any(net.sni.domains[*] in ${"$"}${cloudflare_zero_trust_list.domain_allowlist.id}))" device_posture = "not(any(device_posture.checks.passed[*] in {\"${cloudflare_device_posture_rule.baseline_check.id}\"}))"}
You can add a number of WARP client device posture checks as needed, such as Disk encryption and Domain joined. For more information on device posture checks, refer to Enforce device posture.
Allow HTTPS access for user groups. For example, the following policy gives finance users access to any known financial applications:
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | in list | Finance Servers | And | Allow |
User Group Names | in | Finance Users |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "FinanceUsers-NET-HTTPS-FinanceServers", "description": "Allow HTTPS access for user groups", "precedence": 0, "enabled": true, "action": "allow", "filters": [ "l4" ], "traffic": "net.dst.ip in $<FINANCE_SERVERS_LIST_UUID>", "identity": "any(identity.groups.name[*] in {\"Finance Users\"})"}'
resource "cloudflare_zero_trust_gateway_policy" "finance_users_net_https_finance_servers" { account_id = var.cloudflare_account_id name = "FinanceUsers-NET-HTTPS-FinanceServers" description = "Allow HTTPS access for user groups" precedence = 0 enabled = true action = "allow" filters = ["l4"] traffic = "net.dst.ip in ${"$"}${cloudflare_zero_trust_list.finance_servers_list.id}" identity = "any(identity.groups.name[*] in {\"Finance Users\"})"}
Block traffic to destination IPs, SNIs, and SNI domains that are malicious or pose a threat to your organization.
You can implement this policy by either creating custom blocklists or by using blocklists provided by threat intelligence partners or regional Computer Emergency and Response Teams (CERTs). Ideally, your CERTs can update the blocklist with an API automation to provide real-time threat protection.
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | in list | IP Blocklist | Or | Block |
SNI | in list | Host Blocklist | Or | |
SNI Domain | in list | Domain Blocklist |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "All-NET-Internet-Blocklist", "description": "Block traffic to malicious or risky destination IPs, SNIs, and SNI domains", "precedence": 0, "enabled": true, "action": "block", "filters": [ "l4" ], "traffic": "net.dst.ip in $<IP_BLOCKLIST_UUID> and net.sni.host in $<HOST_BLOCKLIST_UUID> and any(net.sni.domains[*] in $<DOMAIN_BLOCKLIST_UUID>)"}'
resource "cloudflare_zero_trust_gateway_policy" "finance_users_net_https_finance_servers" { account_id = var.cloudflare_account_id name = "All-NET-Internet-Blocklist" description = "Block traffic to malicious or risky destination IPs, SNIs, and SNI domains" precedence = 0 enabled = true action = "block" filters = ["l4"] traffic = "net.dst.ip in ${"$"}${cloudflare_zero_trust_list.ip_blocklist.id} and net.sni.host in ${"$"}${cloudflare_zero_trust_list.host_blocklist.id} and any(net.sni.domains[*] in ${"$"}${cloudflare_zero_trust_list.domain_blocklist.id})"}
Allow SSH traffic to specific endpoints on the Internet for specific users. You can create a similar policy for other non-web endpoints that required access.
Optionally, you can include a selector to filter by source IP or IdP group.
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | in list | SSHAllowList | Or | Allow |
SNI | in list | SSHAllowlistFQDN | And | |
Detected Protocol | is | SSH | And | |
User Group Names | in | SSH-Allowed-Users |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "All-NET-SSH-Internet-Allowlist", "description": "Allow SSH traffic to specific endpoints on the Internet for specific users", "precedence": 0, "enabled": true, "action": "allow", "filters": [ "l4" ], "traffic": "net.dst.ip in $<SSH_IP_ALLOWLIST_UUID> and net.sni.host in $<SSH_FQDN_ALLOWLIST_UUID> and net.detected_protocol == \"ssh\"", "identity": "any(identity.groups.name[*] in {\"SSH-Allowed-Users\"})"}'
resource "cloudflare_zero_trust_gateway_policy" "all_net_ssh_internet_allowlist" { account_id = var.cloudflare_account_id name = "All-NET-SSH-Internet-Allowlist" description = "Allow SSH traffic to specific endpoints on the Internet for specific users" precedence = 0 enabled = true action = "allow" filters = ["l4"] traffic = "net.dst.ip in ${"$"}${cloudflare_zero_trust_list.ssh_ip_allowlist.id} and net.sni.host in ${"$"}${cloudflare_zero_trust_list.ssh_fqdn_allowlist.id} and net.detected_protocol == \"ssh\"" identity = "any(identity.groups.name[*] in {\"SSH-Allowed-Users\"})"}
Block all non-web traffic towards the Internet. By using the Detected Protocol selector, you will ensure alternative ports for HTTP and HTTPS are allowed.
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
Destination IP | not in list | InternalNetwork | And | Block |
Detected Protocol | not in | HTTP, HTTP2 |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "All-NET-NO-HTTP-HTTPS-Internet-Deny", "description": "Block all non-web traffic towards the Internet", "precedence": 0, "enabled": true, "action": "block", "filters": [ "l4" ], "traffic": "not(net.dst.ip in $<INTERNAL_NETWORK_IP_LIST_UUID>) and not(net.detected_protocol in {\"http\" \"http2\"})"}'
resource "cloudflare_zero_trust_gateway_policy" "all_net_no_http_https_internet_deny" { account_id = var.cloudflare_account_id name = "All-NET-NO-HTTP-HTTPS-Internet-Deny" description = "Block all non-web traffic towards the Internet" precedence = 0 enabled = true action = "block" filters = ["l4"] traffic = "not(net.dst.ip in ${"$"}${cloudflare_zero_trust_list.internal_network_ip_list.id}) and not(net.detected_protocol in {\"http\" \"http2\"})"}
Implicitly deny all of your internal IP ranges included in a list. We recommend you place this policy at the bottom of your policy list to ensure you explicitly approve traffic defined in the above policies.
Selector | Operator | Value | Action |
---|---|---|---|
Destination IP | in list | Internal Network IPs | Block |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \--header "Content-Type: application/json" \--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \--data '{ "name": "All-NET-InternalNetwork-ImplicitDeny", "description": "Implicitly deny all of your internal IP ranges included in a list", "precedence": 0, "enabled": true, "action": "block", "filters": [ "l4" ], "traffic": "net.dst.ip in $<INTERNAL_NETWORK_IP_LIST_UUID>"}'
resource "cloudflare_zero_trust_gateway_policy" "all_net_internalnetwork_implicitdeny" { account_id = var.cloudflare_account_id name = "All-NET-InternalNetwork-ImplicitDeny" description = "Implicitly deny all of your internal IP ranges included in a list" precedence = 0 enabled = true action = "block" filters = ["l4"] traffic = "net.dst.ip in ${"$"}${cloudflare_zero_trust_list.internal_network_ip_list.id}"}
Only allow network traffic from known and approved devices.
In the following example, you can use a list of device serial numbers to ensure users can only access an application if they connect with the WARP client from a company device:
Selector | Operator | Value | Logic | Action |
---|---|---|---|---|
SNI Domain | is | internalapp.com | And | Block |
Passed Device Posture Checks | not in | Device serial numbers |
curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/gateway/rules \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --data '{ "name": "All-NET-ApplicationAccess-Allow", "description": "Ensure access to the application comes from authorized WARP clients", "precedence": 5000, "enabled": false, "action": "block", "filters": [ "l4" ], "traffic": "any(net.sni.domains[*] == \"internalapp.com\")", "device_posture": "not(any(device_posture.checks.passed[*] in {\"<DEVICE_SERIAL_NUMBERS_LIST_UUID>\"}))"}'
To get the UUIDs of your device posture checks, use the List device posture rules endpoint.
resource "cloudflare_zero_trust_gateway_policy" "all_net_applicationaccess_allow" { account_id = var.cloudflare_account_id name = "All-NET-ApplicationAccess-Allow" description = "Ensure access to the application comes from authorized WARP clients" precedence = 5000 enabled = false action = "block" filters = ["l4"] traffic = "any(net.sni.domains[*] == \"internalapp.com\")" posture = "not(any(device_posture.checks.passed[*] in {\"${"$"}${cloudflare_zero_trust_list.allowed_devices_sn_list.id}\"}))"}