Skip to main content

octorules-cloudflare

Cloudflare provider for octorules: manages 23 Cloudflare rule phases, custom rulesets, lists, Cloud Connector rules, Page Shield and alerting policies, and the zone settings sections (bot management, security, SSL/TLS, security.txt, managed transforms, and more) as YAML.

Installation

pip install octorules-cloudflare

This installs octorules (core), octorules-cloudflare, and octorules-wirefilter (Rust FFI bridge to Cloudflare's wirefilter engine for authoritative expression parsing and full linter coverage).

Prebuilt wirefilter wheels are available for Linux (x86_64, aarch64; glibc and musl/Alpine), macOS (x86_64, ARM64), and Windows (x86_64).

Configuration

providers:
  cloudflare:
    token: env/CLOUDFLARE_API_TOKEN
  rules:
    directory: ./rules

zones:
  example.com:
    sources:
      - rules

The env/ prefix resolves values from environment variables at runtime. All keys under the provider section are forwarded to the provider constructor as keyword arguments (octodns-style passthrough).

Authentication

A Cloudflare API token is required. See docs/permissions.md for the full list of required permissions per phase and extension.

Provider settings

All settings below go under the provider section (e.g. providers.cloudflare).

Key Default Description
token (required) Cloudflare API token (env/ prefix supported)
max_retries 2 API retry count (0-10)
timeout 30 API timeout in seconds (max 300)

Safety thresholds are configured under safety: (framework-owned, not forwarded to the provider):

Key Default Description
safety.delete_threshold 30.0 Max % of rules that can be deleted
safety.update_threshold 30.0 Max % of rules that can be updated
safety.min_existing 3 Min rules before thresholds apply

Examples

The examples/ directory contains a working single-provider config.yaml plus rules files: rules/example.com.yaml (zone-level) and rules/example-account.yaml (account-level, including the five Magic Transit / Layer-4 phases, whose packet-level expressions are validated against octorules-wirefilter's L4 scheme). Together they exercise every supported phase and key. Copy them as a starting point.

All Cloudflare sections (phases, settings, lists, and policies) nest under a single cloudflare: block.

Supported features

Feature Status
Phase rules (23 phases) Supported
Custom rulesets (account-level) Supported
Lists (IP, ASN, hostname, redirect) Supported
Page Shield policies (zone-level) Supported
Zone discovery (list_zones) Supported
Account-level scopes Supported
Audit IP extraction (octorules audit) Supported
Bot Management settings (bot_management) Supported
URL normalization settings (url_normalization_settings) Supported
Zone security defaults (zone_security) Supported
SSL/TLS settings (zone_tls) Supported
security.txt (security_txt) Supported
Managed Transforms (managed_transforms) Supported
Cloud Connector rules (cloud_connector_rules) Supported
Alerting / notification policies (alerting_policies) Supported
Leaked Credential Check (leaked_credential_check) Supported
Content Scanning / anti-malware (content_scanning) Supported

Supported phases

23 Cloudflare phases — 18 HTTP request/response phases and 5 network-level (Magic Transit) phases. Phases execute in a fixed order:

Request  -> url_normalization -> redirect_rules -> url_rewrite_rules -> request_header_rules
         -> origin_rules -> config_rules -> cache_rules
         -> waf_custom_rules -> waf_managed_rules -> rate_limiting_rules
         -> bot_fight_rules -> http_ddos_rules
         ->  Origin fetch  <-
         -> custom_error_rules -> response_header_rules -> compression_rules
         -> sensitive_data_detection -> log_custom_fields -> Response

Phases with a default action (e.g., redirect_rules -> redirect) don't need action in the YAML — it's injected automatically. For phases without a default (e.g., waf_custom_rules), you must specify action explicitly.

Phases marked as both Zone and Account work at either scope. Account-only phases are skipped for zone scopes and vice versa, eliminating wasted API calls.

For the full phase reference — execution order diagram, valid actions per phase, field/function availability, and key behaviors — see docs/lint/README.md.

Expression syntax

Rule expressions use Cloudflare's ruleset expression language. Expressions are parsed by Cloudflare's actual wirefilter engine via octorules-wirefilter — a required dependency, installed automatically with octorules-cloudflare — providing authoritative type checking, field validation, and syntax verification.

Rule-level metadata: All Cloudflare rules support the octorules: key for per-rule metadata — ignored: true to skip a rule during plan/sync, and included/excluded to restrict rules to specific providers. See octorules core docs for syntax and examples.

Custom rulesets (account-level)

At the account level, WAF custom rules and rate limiting rules use a two-tier structure: the phase entrypoint contains deploy rules (action: execute) that reference child custom rulesets by ID. The individual blocking/logging rules live inside those child rulesets.

octorules manages both tiers. Deploy rules are managed via the normal phase sections (waf_custom_rules, rate_limiting_rules). The individual rules inside each custom ruleset are managed via a separate custom_rulesets section:

# Account rules file (e.g. rules/my-account.yaml)
cloudflare:
  # Deploy rules (phase entrypoint — references child rulesets by ID)
  waf_custom_rules:
    - ref: deploy-known-attackers
      description: Deploy known attackers ruleset
      action: execute
      action_parameters:
        id: abc12345def67890abc12345def67890
        version: latest
      enabled: true
      expression: (http.host eq "api.example.com")

  # Individual rules inside each custom ruleset
  custom_rulesets:
    - id: abc12345def67890abc12345def67890
      name: Known attackers
      phase: http_request_firewall_custom
      rules:
        - ref: block-bad-asn
          description: Block by AS number
          action: block
          expression: (ip.geoip.asnum in {12345 67890})
        - ref: block-bad-ua
          description: Block by user-agent
          action: block
          expression: (http.user_agent contains "BadBot")

The id field in each custom_rulesets entry links it to the deploy rule's action_parameters.id. Rules inside use ref for identification (same pattern as phase rules). Every rule must specify an action explicitly.

Use octorules dump --scope account to export existing custom rulesets to YAML.

Note: octorules manages rules within existing custom rulesets. Creating or deleting rulesets themselves must be done via the Cloudflare dashboard. Zone-level rulesets do not have kind=custom children — this is account-level only.

Lists (account-level)

Cloudflare account-level Lists (IP lists, ASN lists, hostname lists, redirect lists) can be referenced in rule expressions via $list_name syntax. octorules manages full lifecycle of lists declaratively: create, delete, update metadata, and manage items.

Add a lists key under the cloudflare: block of your account rules file:

# rules/my-account.yaml
cloudflare:
  lists:
    - name: blocked_ips
      kind: ip
      description: "Known bad IPs"
      items:
        - ip: "1.2.3.4"
          comment: "Scanner"
        - ip: "5.6.7.0/24"
          comment: "Botnet range"

    - name: partner_asns
      kind: asn
      description: "Partner AS numbers"
      items:
        - asn: 12345
          comment: "Partner A"
        - asn: 67890
          comment: "Partner B"

Each list entry requires:

Field Description
name List name — matches CF list name and $list_name in expressions
kind One of ip, asn, hostname, redirect
description Optional — updated if changed
items List of items (can be empty [] to clear all items)

How it works:

  • The presence of a lists: key means ALL lists are managed — lists in Cloudflare not in YAML are planned for deletion (subject to safety thresholds).
  • If the lists: key is absent, lists are ignored entirely.
  • Item updates are asynchronous — octorules polls the bulk operation until completion.
  • During sync, lists are applied before rulesets and phases, so newly created lists are available for rule expressions that reference them.
  • Use octorules dump --scope account to export existing lists to YAML. The dump externalizes list items into separate files (referenced via !include tags) under providers.lists.directory (default: {rules_dir}/custom_lists).

Reference lists in rule expressions:

cloudflare:
  waf_custom_rules:
    - ref: block-bad-ips
      description: Block IPs from blocklist
      action: block
      expression: (ip.src in $blocked_ips)

Page Shield policies (zone-level)

Cloudflare Page Shield manages Content Security Policies (CSP) at the zone level. octorules manages full lifecycle of Page Shield policies declaratively: create, update, and delete.

Add a page_shield_policies key under the cloudflare: block of your zone rules file:

# rules/example.com.yaml
cloudflare:
  page_shield_policies:
    - description: "CSP on all example.com"
      action: allow
      expression: "true"
      enabled: true
      value: >-
        script-src 'self' 'unsafe-inline' 'unsafe-eval' https:;
        worker-src 'self' blob:

    - description: "Log CSP on staging"
      action: log
      expression: '(http.host eq "staging.example.com")'
      enabled: true
      value: "default-src 'self'"

Each policy entry requires:

Field Description
description Policy description — used as the identity key for matching
action allow or log
expression Cloudflare filter expression
enabled Boolean
value CSP directive string

How it works:

  • The description field is the identity key (like ref for rules and name for lists). Policies are matched between YAML and Cloudflare by description.
  • The presence of a page_shield_policies: key means ALL policies are managed - policies in Cloudflare not in YAML are planned for deletion.
  • If the page_shield_policies: key is absent, policies are ignored entirely.
  • During sync, policies are applied after lists and before custom rulesets and phases.
  • Use octorules dump to export existing Page Shield policies to YAML.

CSP source normalization: The order of sources within a CSP directive is not significant — script-src 'self' example.com and script-src example.com 'self' are semantically identical. octorules normalizes source order (sorted alphabetically within each directive) before comparing value fields, so reordering sources in your YAML will not trigger an upstream change on Cloudflare. You can freely reorganize sources for readability without causing a sync.

Cloud Connector rules (zone-level)

Cloudflare Cloud Connector routes matching requests directly to an object-storage provider. octorules manages the zone's rule list declaratively.

Add a cloud_connector_rules key under the cloudflare: block of your zone rules file:

# rules/example.com.yaml
cloudflare:
  cloud_connector_rules:
    - description: "Serve /assets from the R2 bucket"
      expression: 'starts_with(http.request.uri.path, "/assets/")'
      provider: cloudflare_r2
      parameters:
        host: assets.account-a.r2.cloudflarestorage.com

Each rule entry:

Field Description
description Rule description, used as the identity key for matching
expression Cloudflare filter expression (request-phase fields)
provider aws_s3, cloudflare_r2, gcp_storage, or azure_storage
parameters Provider parameters (host: the storage endpoint to route to)
enabled Boolean, defaults to true

How it works:

  • The description field is the identity key (like description for Page Shield policies): the Cloud Connector API has no ref field to persist, so plans match YAML rules to live rules by description. Descriptions must be unique.
  • Rule order is part of the desired state: reordering rules in YAML is a planned change.
  • The presence of a cloud_connector_rules: key means ALL rules are managed - the list is replaced wholesale on sync, so rules in Cloudflare not in YAML are planned for deletion. If the key is absent, Cloud Connector is ignored entirely.
  • Use octorules dump to export existing Cloud Connector rules to YAML.

Alerting policies (account-level)

Cloudflare notification policies decide who gets told when something happens: a certificate about to expire, an L7 DDoS event, a Cloudflare incident. They live on the account, so the section belongs in the account-scoped rules file:

# rules/account-a.yaml
cloudflare:
  alerting_policies:
    - name: "Certificate expiring soon"
      alert_type: dedicated_ssl_certificate_event_type
      enabled: true
      mechanisms:
        email: ["security@account-a.example"]
        webhooks: ["$Ops Slack"]

Each policy entry:

Field Description
name Policy name, used as the identity key for matching
alert_type One of the account's available alert types
enabled Boolean
mechanisms Destinations: email (addresses), webhooks ($name references or ids), pagerduty (ids); at least one required
description Optional
alert_interval Optional re-alert interval
filters Optional per-type filters; zones entries are zone names

How it works:

  • The name field is the identity key. Policies are matched between YAML and Cloudflare by name; names must be unique.
  • Webhook destinations are referenced by name with a $ prefix ("$Ops Slack") and resolved against the account's webhook destinations at plan time. Destinations themselves are not managed; create them once in the dashboard.
  • Zone names inside filters.zones are resolved to zone ids on plan and translated back on dump, so the YAML does not need to carry UUIDs.
  • alert_type and each type's required filters are validated at plan time against the account's own available_alerts registry, not a hardcoded table: an alert type this account cannot use, or a missing required filter, fails the plan before the API rejects it.
  • The presence of an alerting_policies: key means ALL policies are managed - policies in Cloudflare not in YAML are planned for deletion. If the key is absent, alerting is ignored entirely.
  • Fields the YAML declares replace the live value; optional fields it omits keep their dashboard-set values.
  • Use octorules dump to export existing policies to YAML.

Linting

168 Cloudflare-specific lint rules (CF prefix) across 6 ranges:

Range Category Rules
CF001–CF027 Structure, parse & phase 25
CF100–CF105 Cross-rule ordering 6
CF200–CF227 Action validation 28
CF300–CF309 Expression, function & type 10
CF400–CF495 Domain-specific (rate limit, cache, config, redirect, transform, origin, page shield, list, cloud connector) 56
CF500–CF550 Plan limits, style & value constraints 43

See docs/lint/README.md for the full rule reference.

Development

git clone git@github.com:doctena-org/octorules-cloudflare.git
cd octorules-cloudflare
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pre-commit install

The pre-commit hook runs ruff (check + format) and yamllint. See docs/schemas.md for the schema architecture — octorules-wirefilter provides the field/function data and is a required dependency (there is no frozen fallback).

License

octorules-cloudflare is licensed under the Apache License 2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

octorules_cloudflare-0.17.0.tar.gz (218.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

octorules_cloudflare-0.17.0-py3-none-any.whl (157.8 kB view details)

Uploaded Python 3

File details

Details for the file octorules_cloudflare-0.17.0.tar.gz.

File metadata

  • Download URL: octorules_cloudflare-0.17.0.tar.gz
  • Upload date:
  • Size: 218.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for octorules_cloudflare-0.17.0.tar.gz
Algorithm Hash digest
SHA256 d350551eb62b7d23271b04c4d20f283db13ff91d3b11b49d7010f81b63f82454
MD5 f2a7dcadbfbb050b7c154c56dfa02c2a
BLAKE2b-256 36893517d0c1536657e869303435d2d98bb13df6d5cfadd65c0be27564543fca

See more details on using hashes here.

Provenance

The following attestation bundles were made for octorules_cloudflare-0.17.0.tar.gz:

Publisher: release.yaml on doctena-org/octorules-cloudflare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file octorules_cloudflare-0.17.0-py3-none-any.whl.

File metadata

File hashes

Hashes for octorules_cloudflare-0.17.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f6299330433a018c0512a1f887b259ec0b49ee589712c04abe4c18a6c3fb5e1f
MD5 5dab105f4c674a8c8ed04c554d416e26
BLAKE2b-256 2bb698d4ddfa922c9a2aab2d7dc0df29e47cca64471b1e4f4ca99bbfff1ee3a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for octorules_cloudflare-0.17.0-py3-none-any.whl:

Publisher: release.yaml on doctena-org/octorules-cloudflare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.17.0 This release

2 files

0.16.0

2 files

0.15.0

2 files

0.14.0

2 files

0.13.0

2 files

0.12.2

2 files

0.12.1

2 files

0.12.0

2 files

0.11.1

2 files

0.11.0

2 files

0.10.0

2 files

0.9.0

2 files

0.8.9

2 files

0.8.8

2 files

0.8.7

2 files

0.8.6

2 files

0.8.5

2 files

0.8.3

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.12

2 files

0.7.11

2 files

0.7.10

2 files

0.7.9

2 files

0.7.8

2 files

0.7.7

2 files

0.7.6

2 files

0.7.5

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.1

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page