@gfargo/doorman 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/doorman/.source-version +1 -0
- package/skills/doorman/SKILL.md +74 -77
- package/skills/doorman/references/cicd.md +240 -0
- package/skills/doorman/references/cloudflare.md +188 -0
- package/skills/doorman/references/rules.md +352 -0
- package/skills/doorman/references/templates.md +191 -0
- package/skills/doorman/sync/README.md +43 -0
- package/skills/doorman/sync/plugin.json +23 -0
- package/skills/doorman/sync/sync-doorman.yml +80 -0
- package/skills/doorman/rules-reference.md +0 -478
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v3.1.0
|
package/skills/doorman/SKILL.md
CHANGED
|
@@ -1,33 +1,47 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: doorman
|
|
3
|
-
description:
|
|
3
|
+
description: Manage Vercel and Cloudflare WAF firewall rules as code with the Doorman CLI. Use for any firewall-as-code task — creating rules, IP blocking, rate limiting, bot protection, geo-blocking, syncing local config to providers, validating configurations, exporting documentation, CI/CD automation, or translating rules between Vercel and Cloudflare formats.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Node.js >= 20. Requires provider API tokens (VERCEL_TOKEN or CLOUDFLARE_API_TOKEN). Install globally via npm install -g @gfargo/doorman.
|
|
6
|
+
metadata:
|
|
7
|
+
author: gfargo
|
|
8
|
+
version: "1.0"
|
|
9
|
+
homepage: https://github.com/gfargo/doorman
|
|
10
|
+
npm: "@gfargo/doorman"
|
|
4
11
|
---
|
|
5
12
|
|
|
6
|
-
# Doorman
|
|
13
|
+
# Doorman — Firewall Rules as Code
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
Doorman is a CLI for managing WAF (Web Application Firewall) rules as code across Vercel and Cloudflare. Configuration lives in `.doorman.json`, syncs bidirectionally with provider APIs, and integrates into CI/CD pipelines.
|
|
9
16
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
- **Config file**: `.doorman.json` (also supports legacy `vercel-firewall.config.json`)
|
|
13
|
-
- **Providers**: Vercel (default) and Cloudflare (`--provider cloudflare`)
|
|
14
|
-
- **Workflow**: Edit config → validate → diff → sync
|
|
15
|
-
- **Schema**: `https://doorman.griffen.codes/schema.json`
|
|
16
|
-
|
|
17
|
-
## Commands
|
|
17
|
+
## Command Quick Reference
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
21
|
-
doorman
|
|
22
|
-
doorman
|
|
23
|
-
doorman
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
doorman
|
|
27
|
-
doorman
|
|
28
|
-
doorman
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
# Setup & Init
|
|
21
|
+
doorman setup # Show setup guide with links
|
|
22
|
+
doorman init --interactive # Create new config interactively
|
|
23
|
+
doorman init security-focused # Start with security templates
|
|
24
|
+
|
|
25
|
+
# Rule Creation
|
|
26
|
+
doorman add --interactive # Guided rule creation
|
|
27
|
+
doorman add --name "Block" --field path --op pre --value "/admin" --action deny
|
|
28
|
+
doorman template ai-bots # Add pre-built template
|
|
29
|
+
|
|
30
|
+
# Status & Inspection
|
|
31
|
+
doorman status # Sync status + health score
|
|
32
|
+
doorman list # Show deployed rules (table/json)
|
|
33
|
+
doorman diff # Local vs remote differences
|
|
34
|
+
|
|
35
|
+
# Sync & Deploy
|
|
36
|
+
doorman validate # Check config syntax + health
|
|
37
|
+
doorman sync # Deploy local config to provider
|
|
38
|
+
doorman download # Pull remote rules to local config
|
|
39
|
+
|
|
40
|
+
# Advanced
|
|
41
|
+
doorman watch # Auto-sync on file changes
|
|
42
|
+
doorman backup # Create/restore config backups
|
|
43
|
+
doorman export --format markdown # Export as markdown|json|yaml|terraform
|
|
44
|
+
doorman remove --name "Old Rule" # Remove rules by name/ID
|
|
31
45
|
```
|
|
32
46
|
|
|
33
47
|
All commands accept `--provider vercel|cloudflare` and `--config <path>`.
|
|
@@ -35,15 +49,15 @@ All commands accept `--provider vercel|cloudflare` and `--config <path>`.
|
|
|
35
49
|
## Environment Variables
|
|
36
50
|
|
|
37
51
|
```bash
|
|
38
|
-
# Vercel
|
|
52
|
+
# Vercel (default provider)
|
|
39
53
|
VERCEL_TOKEN=your_token
|
|
40
54
|
VERCEL_PROJECT_ID=prj_xxx
|
|
41
55
|
VERCEL_TEAM_ID=team_xxx
|
|
42
56
|
|
|
43
|
-
# Cloudflare
|
|
57
|
+
# Cloudflare (beta)
|
|
44
58
|
CLOUDFLARE_API_TOKEN=your_token
|
|
45
59
|
CLOUDFLARE_ZONE_ID=zone_xxx
|
|
46
|
-
CLOUDFLARE_ACCOUNT_ID=acc_xxx
|
|
60
|
+
CLOUDFLARE_ACCOUNT_ID=acc_xxx # optional, enables Lists API for bulk IP management
|
|
47
61
|
```
|
|
48
62
|
|
|
49
63
|
## Config Structure
|
|
@@ -58,75 +72,58 @@ CLOUDFLARE_ACCOUNT_ID=acc_xxx # optional, enables Lists API
|
|
|
58
72
|
}
|
|
59
73
|
```
|
|
60
74
|
|
|
61
|
-
For Cloudflare,
|
|
75
|
+
For Cloudflare, add `provider` and `providers` fields instead of `projectId`/`teamId`.
|
|
76
|
+
|
|
77
|
+
## Core Workflow
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Edit .doorman.json (add/modify rules), then:
|
|
81
|
+
doorman validate && doorman diff && doorman sync
|
|
82
|
+
|
|
83
|
+
# Pull existing rules from a live provider:
|
|
84
|
+
doorman download
|
|
85
|
+
|
|
86
|
+
# Safe production deployment:
|
|
87
|
+
doorman backup && doorman validate && doorman diff && doorman sync && doorman status
|
|
88
|
+
```
|
|
62
89
|
|
|
63
|
-
## Rule
|
|
90
|
+
## Rule Shape (Minimal)
|
|
64
91
|
|
|
65
92
|
```json
|
|
66
93
|
{
|
|
67
|
-
"
|
|
68
|
-
"name": "Block Admin Access",
|
|
69
|
-
"description": "Block unauthorized admin access",
|
|
94
|
+
"name": "Block Admin",
|
|
70
95
|
"active": true,
|
|
71
96
|
"conditionGroup": [
|
|
72
|
-
{
|
|
73
|
-
"conditions": [
|
|
74
|
-
{ "type": "path", "op": "pre", "value": "/admin" },
|
|
75
|
-
{ "type": "method", "op": "eq", "value": "POST" }
|
|
76
|
-
]
|
|
77
|
-
}
|
|
97
|
+
{ "conditions": [{ "type": "path", "op": "pre", "value": "/admin" }] }
|
|
78
98
|
],
|
|
79
|
-
"action": {
|
|
80
|
-
"mitigate": {
|
|
81
|
-
"action": "deny"
|
|
82
|
-
}
|
|
83
|
-
}
|
|
99
|
+
"action": { "mitigate": { "action": "deny" } }
|
|
84
100
|
}
|
|
85
101
|
```
|
|
86
102
|
|
|
87
103
|
**Logic**: Conditions within a group are AND'd. Multiple groups are OR'd.
|
|
88
104
|
|
|
89
|
-
**Condition types**: `path`, `method`, `host`, `user_agent`, `ip_address`, `header`, `query`, `cookie`, `geo_country`, `geo_city`, `geo_continent`, `scheme`
|
|
105
|
+
**Condition types**: `path`, `method`, `host`, `user_agent`, `ip_address`, `header`, `query`, `cookie`, `geo_country`, `geo_city`, `geo_continent`, `geo_country_region`, `geo_as_number`, `scheme`, `protocol`
|
|
90
106
|
|
|
91
|
-
**Operators**: `eq`, `pre` (
|
|
107
|
+
**Operators**: `eq`, `pre` (prefix), `suf` (suffix), `sub` (contains), `inc` (in array), `re` (regex), `ex` (exists), `nex` (not exists)
|
|
92
108
|
|
|
93
109
|
**Actions**: `deny`, `challenge`, `rate_limit`, `redirect`, `log`, `bypass`
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
## IP Blocking
|
|
98
|
-
|
|
99
|
-
```json
|
|
100
|
-
{
|
|
101
|
-
"ips": [{ "ip": "192.168.1.0/24", "action": "deny", "hostname": "bad-subnet", "notes": "Blocked for abuse" }]
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Templates
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
doorman template bad-bots # Block malicious bots
|
|
109
|
-
doorman template ai-bots # Block AI crawlers
|
|
110
|
-
doorman template wordpress # Block WordPress attack paths
|
|
111
|
-
doorman template block-ofac-sanctioned-countries # OFAC compliance
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Workflow
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
# Add a rule: edit .doorman.json, then:
|
|
118
|
-
doorman validate && doorman sync
|
|
111
|
+
## When to Read Each Reference
|
|
119
112
|
|
|
120
|
-
|
|
121
|
-
doorman download
|
|
113
|
+
Load the relevant reference file for detailed documentation:
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
115
|
+
| Task | Reference |
|
|
116
|
+
|------|-----------|
|
|
117
|
+
| Writing rules — full field docs, operators, actions, IP blocking, patterns | [references/rules.md](references/rules.md) |
|
|
118
|
+
| Cloudflare-specific setup, Lists API, expression translation, limitations | [references/cloudflare.md](references/cloudflare.md) |
|
|
119
|
+
| Available templates and what they protect against | [references/templates.md](references/templates.md) |
|
|
120
|
+
| CI/CD integration, automation, export formats, validation in pipelines | [references/cicd.md](references/cicd.md) |
|
|
126
121
|
|
|
127
|
-
##
|
|
122
|
+
## Principles
|
|
128
123
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
1. **Validate before syncing** — always run `doorman validate` before `doorman sync`.
|
|
125
|
+
2. **Diff before deploying** — use `doorman diff` to preview what will change on the provider.
|
|
126
|
+
3. **Backup before major changes** — `doorman backup` creates a timestamped snapshot.
|
|
127
|
+
4. **Config is the source of truth** — make changes in `.doorman.json`, let sync propagate them.
|
|
128
|
+
5. **Use templates for common patterns** — `doorman template` has battle-tested rules for bots, geo-blocking, and attack paths.
|
|
129
|
+
6. **Health score matters** — add descriptions, use IDs with `rule_` prefix, avoid regex when simpler operators work.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# CI/CD & Automation Reference
|
|
2
|
+
|
|
3
|
+
Integrating Doorman into automated pipelines, export formats, and programmatic usage.
|
|
4
|
+
|
|
5
|
+
## CI/CD Pipeline Integration
|
|
6
|
+
|
|
7
|
+
Doorman commands return structured output and meaningful exit codes for automation.
|
|
8
|
+
|
|
9
|
+
### Validation in CI
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Fail the build if config is invalid
|
|
13
|
+
doorman validate --config .doorman.json
|
|
14
|
+
# Exit 0 = valid, Exit 1 = validation errors
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Diff Check (Detect Changes)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Check if local config differs from deployed
|
|
21
|
+
doorman diff --format json --config .doorman.json
|
|
22
|
+
# Exit 0 = differences found (outputs JSON), Exit 1 = error
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Automated Sync
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Deploy rules non-interactively
|
|
29
|
+
doorman sync --config .doorman.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Full Pipeline Example (GitHub Actions)
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
name: Deploy Firewall Rules
|
|
36
|
+
on:
|
|
37
|
+
push:
|
|
38
|
+
branches: [main]
|
|
39
|
+
paths: ['.doorman.json']
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
deploy:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- uses: actions/setup-node@v4
|
|
48
|
+
with:
|
|
49
|
+
node-version: '20'
|
|
50
|
+
|
|
51
|
+
- run: npm install -g @gfargo/doorman
|
|
52
|
+
|
|
53
|
+
- name: Validate
|
|
54
|
+
run: doorman validate --config .doorman.json
|
|
55
|
+
|
|
56
|
+
- name: Preview Changes
|
|
57
|
+
run: doorman diff --format json --config .doorman.json || true
|
|
58
|
+
|
|
59
|
+
- name: Deploy
|
|
60
|
+
run: doorman sync --config .doorman.json
|
|
61
|
+
env:
|
|
62
|
+
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
|
|
63
|
+
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
64
|
+
VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cloudflare Pipeline
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
- name: Deploy to Cloudflare
|
|
71
|
+
run: doorman sync --provider cloudflare --config .doorman.json
|
|
72
|
+
env:
|
|
73
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
74
|
+
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
|
|
75
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Export Formats
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
doorman export --format json # JSON (default)
|
|
82
|
+
doorman export --format yaml # YAML
|
|
83
|
+
doorman export --format markdown # Human-readable Markdown
|
|
84
|
+
doorman export --format terraform # Terraform HCL
|
|
85
|
+
doorman export --output firewall-docs.md # Write to file
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### JSON Export
|
|
89
|
+
|
|
90
|
+
Full config dump, useful for backup or diffing:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
doorman export --format json > firewall-backup.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### YAML Export
|
|
97
|
+
|
|
98
|
+
Human-friendly format for documentation:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
doorman export --format yaml --output firewall.yaml
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Markdown Export
|
|
105
|
+
|
|
106
|
+
Generate team-readable documentation:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
doorman export --format markdown --output FIREWALL.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Produces a table of all rules with their conditions, actions, and status.
|
|
113
|
+
|
|
114
|
+
### Terraform Export
|
|
115
|
+
|
|
116
|
+
Generate Terraform HCL for infrastructure-as-code repositories:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
doorman export --format terraform --output firewall.tf
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Backup & Restore
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Create a timestamped backup
|
|
126
|
+
doorman backup
|
|
127
|
+
|
|
128
|
+
# List all backups
|
|
129
|
+
doorman backup --list
|
|
130
|
+
|
|
131
|
+
# Restore from a backup
|
|
132
|
+
doorman backup --restore <filename>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Backups are stored locally as JSON files. Include backup creation in your deployment pipeline as a safety net.
|
|
136
|
+
|
|
137
|
+
## Watch Mode (Development)
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Auto-validate and sync on file changes
|
|
141
|
+
doorman watch
|
|
142
|
+
|
|
143
|
+
# Watch a specific config
|
|
144
|
+
doorman watch --config .doorman.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Watch mode is for development only — it syncs immediately on save. Do not use in production pipelines.
|
|
148
|
+
|
|
149
|
+
## Programmatic Usage (Node.js)
|
|
150
|
+
|
|
151
|
+
Doorman can be used as a library in Node.js applications:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { createDoorman } from '@gfargo/doorman/next'
|
|
155
|
+
|
|
156
|
+
// Next.js middleware integration
|
|
157
|
+
const doorman = createDoorman({
|
|
158
|
+
// Configuration options
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Status & Health Monitoring
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Check sync status and configuration health
|
|
166
|
+
doorman status
|
|
167
|
+
|
|
168
|
+
# Machine-readable status
|
|
169
|
+
doorman status --format json
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The health score evaluates:
|
|
173
|
+
- Rule descriptions present
|
|
174
|
+
- ID conventions followed (`rule_` prefix)
|
|
175
|
+
- Operator complexity (penalizes unnecessary regex)
|
|
176
|
+
- Active/inactive rule ratio
|
|
177
|
+
- Bot protection coverage
|
|
178
|
+
- Rate limiting coverage
|
|
179
|
+
|
|
180
|
+
## Multi-Environment Strategies
|
|
181
|
+
|
|
182
|
+
### Separate configs per environment
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Production
|
|
186
|
+
doorman sync --config .doorman.prod.json
|
|
187
|
+
|
|
188
|
+
# Staging (lighter rules)
|
|
189
|
+
doorman sync --config .doorman.staging.json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Single config, different providers
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Same rules, different targets
|
|
196
|
+
doorman sync --provider vercel --config .doorman.json
|
|
197
|
+
doorman sync --provider cloudflare --config .doorman.json
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Download from one, deploy to another
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Migrate rules between providers
|
|
204
|
+
doorman download --provider vercel --config .doorman.json
|
|
205
|
+
doorman validate --provider cloudflare --config .doorman.json
|
|
206
|
+
doorman sync --provider cloudflare --config .doorman.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Command Flags Reference
|
|
210
|
+
|
|
211
|
+
Global flags available on all commands:
|
|
212
|
+
|
|
213
|
+
| Flag | Description |
|
|
214
|
+
|------|-------------|
|
|
215
|
+
| `--config <path>` | Path to config file (default: auto-discovered `.doorman.json`) |
|
|
216
|
+
| `--provider vercel\|cloudflare` | Override provider detection |
|
|
217
|
+
| `--format json\|table\|yaml\|markdown\|terraform` | Output format (command-dependent) |
|
|
218
|
+
| `--verbose` | Show detailed output |
|
|
219
|
+
| `--output <path>` | Write output to file instead of stdout |
|
|
220
|
+
|
|
221
|
+
## Error Handling in Automation
|
|
222
|
+
|
|
223
|
+
Doorman exit codes:
|
|
224
|
+
- `0` — success
|
|
225
|
+
- `1` — error (validation failure, API error, config not found)
|
|
226
|
+
|
|
227
|
+
Errors are written to stderr in a structured format. In CI, capture stderr for diagnostics:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
doorman sync 2> sync-errors.log || { cat sync-errors.log; exit 1; }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Security Best Practices for CI/CD
|
|
234
|
+
|
|
235
|
+
1. **Never commit tokens** — use CI secrets/environment variables exclusively
|
|
236
|
+
2. **Validate before deploy** — always run `doorman validate` as a gate before `doorman sync`
|
|
237
|
+
3. **Use `doorman diff`** — review changes in PR checks before merge triggers deployment
|
|
238
|
+
4. **Backup before sync** — automate `doorman backup` before every `doorman sync` in production
|
|
239
|
+
5. **Pin the doorman version** — use `npm install -g @gfargo/doorman@3.x` to avoid unexpected breaking changes
|
|
240
|
+
6. **Limit token scope** — use the narrowest API token permissions possible (project-scoped for Vercel, zone-scoped for Cloudflare)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Cloudflare Provider Reference
|
|
2
|
+
|
|
3
|
+
Cloudflare WAF support in Doorman (beta). Manage Cloudflare custom rulesets and IP Lists through the same config-as-code workflow.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### Environment Variables
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
CLOUDFLARE_API_TOKEN=your_token # Required — API token with Zone.Firewall permissions
|
|
11
|
+
CLOUDFLARE_ZONE_ID=zone_xxx # Required — zone to manage rules for
|
|
12
|
+
CLOUDFLARE_ACCOUNT_ID=acc_xxx # Optional — enables Lists API for bulk IP management
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### API Token Permissions
|
|
16
|
+
|
|
17
|
+
Create a Custom Token at https://dash.cloudflare.com/profile/api-tokens with:
|
|
18
|
+
- **Zone > Firewall Services > Edit** — for custom rulesets
|
|
19
|
+
- **Account > Account Filter Lists > Edit** — for Lists API (bulk IP management, requires `CLOUDFLARE_ACCOUNT_ID`)
|
|
20
|
+
|
|
21
|
+
### Config Shape
|
|
22
|
+
|
|
23
|
+
Multi-provider config with explicit provider declaration:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"$schema": "https://doorman.griffen.codes/schema.json",
|
|
28
|
+
"provider": "cloudflare",
|
|
29
|
+
"providers": {
|
|
30
|
+
"cloudflare": {
|
|
31
|
+
"zoneId": "your_zone_id",
|
|
32
|
+
"accountId": "your_account_id"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"rules": [],
|
|
36
|
+
"ips": []
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or pass `--provider cloudflare` to any command to override the default.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
doorman init --provider cloudflare # Initialize Cloudflare config
|
|
46
|
+
doorman validate --provider cloudflare # Validate against Cloudflare constraints
|
|
47
|
+
doorman sync --provider cloudflare # Deploy to Cloudflare
|
|
48
|
+
doorman download --provider cloudflare # Pull rules from Cloudflare
|
|
49
|
+
doorman diff --provider cloudflare # Compare local vs live
|
|
50
|
+
doorman list --provider cloudflare # Show deployed rules
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Rule Translation
|
|
54
|
+
|
|
55
|
+
Doorman translates its unified rule format into Cloudflare Wirefilter expressions automatically. The translation is bidirectional — `doorman download` pulls Cloudflare expressions back into the unified format.
|
|
56
|
+
|
|
57
|
+
### Field Mapping
|
|
58
|
+
|
|
59
|
+
| Doorman Type | Cloudflare Field |
|
|
60
|
+
|-------------|------------------|
|
|
61
|
+
| `path` | `http.request.uri.path` |
|
|
62
|
+
| `method` | `http.request.method` |
|
|
63
|
+
| `host` | `http.host` |
|
|
64
|
+
| `user_agent` | `http.user_agent` |
|
|
65
|
+
| `ip_address` | `ip.src` |
|
|
66
|
+
| `header` | `http.request.headers["key"]` |
|
|
67
|
+
| `query` | `http.request.uri.query` |
|
|
68
|
+
| `cookie` | `http.cookie` |
|
|
69
|
+
| `geo_country` | `ip.geoip.country` |
|
|
70
|
+
| `geo_city` | `ip.geoip.city` |
|
|
71
|
+
| `geo_continent` | `ip.geoip.continent` |
|
|
72
|
+
| `geo_country_region` | `ip.geoip.subdivision_1` |
|
|
73
|
+
| `geo_as_number` | `ip.geoip.asnum` |
|
|
74
|
+
| `scheme` | `ssl` (boolean) |
|
|
75
|
+
|
|
76
|
+
### Action Mapping
|
|
77
|
+
|
|
78
|
+
| Doorman Action | Cloudflare Action |
|
|
79
|
+
|---------------|-------------------|
|
|
80
|
+
| `deny` | `block` |
|
|
81
|
+
| `challenge` | `managed_challenge` |
|
|
82
|
+
| `rate_limit` | `block` + `ratelimit` config |
|
|
83
|
+
| `redirect` | `redirect` + `from_value` params |
|
|
84
|
+
| `log` | `log` |
|
|
85
|
+
| `bypass` | `skip` |
|
|
86
|
+
|
|
87
|
+
## Lists API (Bulk IP Management)
|
|
88
|
+
|
|
89
|
+
When `CLOUDFLARE_ACCOUNT_ID` is set, IP rules in the `ips` array are managed via Cloudflare's Lists API — a dedicated service for bulk IP blocking that scales better than individual rules.
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# IPs in config are synced to a Cloudflare List
|
|
93
|
+
doorman sync --provider cloudflare
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Without `CLOUDFLARE_ACCOUNT_ID`, IP blocking falls back to individual WAF rules with `ip.src` expressions — functional but limited by rule count quotas.
|
|
97
|
+
|
|
98
|
+
## Limitations & Differences
|
|
99
|
+
|
|
100
|
+
| Feature | Vercel | Cloudflare | Notes |
|
|
101
|
+
|---------|--------|------------|-------|
|
|
102
|
+
| `re` operator | All plans | Enterprise only | Use `sub`/`pre`/`suf` as alternatives |
|
|
103
|
+
| `environment` type | Yes | No | Vercel-specific concept |
|
|
104
|
+
| `ja3_digest`/`ja4_digest` | Yes | No | Vercel TLS fingerprints |
|
|
105
|
+
| `region` type | Yes | No | Vercel edge region |
|
|
106
|
+
| IP Lists (bulk) | Individual rules | Lists API | Cloudflare needs `accountId` |
|
|
107
|
+
| Max custom rules | ~100 | 5-125 (plan dependent) | Free: 5, Pro: 20, Business: 100, Enterprise: 125+ |
|
|
108
|
+
| Rate limit | Via rule action | Separate phase | Different underlying mechanism |
|
|
109
|
+
| Rule order | Parallel evaluation | Sequential (first match wins) | Ordering matters on Cloudflare |
|
|
110
|
+
|
|
111
|
+
## Translation Warnings
|
|
112
|
+
|
|
113
|
+
The `RuleTranslator` surfaces warnings when a translation is lossy:
|
|
114
|
+
|
|
115
|
+
- **Regex on non-Enterprise** — `re` operator only works on Cloudflare Enterprise; downgraded to `contains` with a warning
|
|
116
|
+
- **Unsupported types** — Vercel-only fields (`environment`, `ja3_digest`, `ja4_digest`, `region`) are dropped with a warning
|
|
117
|
+
- **Duration differences** — `actionDuration` maps differently between providers
|
|
118
|
+
- **Negation edge cases** — complex negated conditions may produce subtly different behavior in Wirefilter
|
|
119
|
+
|
|
120
|
+
Run `doorman validate --provider cloudflare` to surface warnings before deploying.
|
|
121
|
+
|
|
122
|
+
## Cloudflare-Specific Validation
|
|
123
|
+
|
|
124
|
+
Doorman validates Cloudflare configs against:
|
|
125
|
+
|
|
126
|
+
- Expression syntax (Wirefilter grammar)
|
|
127
|
+
- Rule count limits per plan
|
|
128
|
+
- Action compatibility (e.g., `js_challenge` deprecated in favor of `managed_challenge`)
|
|
129
|
+
- List reference validity (when using Lists API)
|
|
130
|
+
- Rate limit configuration completeness
|
|
131
|
+
|
|
132
|
+
## Optimizer
|
|
133
|
+
|
|
134
|
+
The `CloudflareOptimizer` consolidates rules for efficient deployment:
|
|
135
|
+
|
|
136
|
+
- Merges rules with identical actions into single expressions using `or`
|
|
137
|
+
- Deduplicates IP entries across rules and Lists
|
|
138
|
+
- Computes minimal changesets to avoid unnecessary API calls (diff-based sync)
|
|
139
|
+
|
|
140
|
+
## Example: Full Cloudflare Config
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"$schema": "https://doorman.griffen.codes/schema.json",
|
|
145
|
+
"provider": "cloudflare",
|
|
146
|
+
"providers": {
|
|
147
|
+
"cloudflare": {
|
|
148
|
+
"zoneId": "abc123def456",
|
|
149
|
+
"accountId": "acc789xyz"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"rules": [
|
|
153
|
+
{
|
|
154
|
+
"id": "rule_block_bots",
|
|
155
|
+
"name": "Block Bad Bots",
|
|
156
|
+
"description": "Block known malicious crawlers",
|
|
157
|
+
"active": true,
|
|
158
|
+
"conditionGroup": [
|
|
159
|
+
{ "conditions": [{ "type": "user_agent", "op": "sub", "value": "AhrefsBot" }] },
|
|
160
|
+
{ "conditions": [{ "type": "user_agent", "op": "sub", "value": "SemrushBot" }] }
|
|
161
|
+
],
|
|
162
|
+
"action": { "mitigate": { "action": "deny" } }
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": "rule_rate_limit_api",
|
|
166
|
+
"name": "Rate Limit API",
|
|
167
|
+
"description": "Limit API requests to 100/min per IP",
|
|
168
|
+
"active": true,
|
|
169
|
+
"conditionGroup": [
|
|
170
|
+
{ "conditions": [{ "type": "path", "op": "pre", "value": "/api/" }] }
|
|
171
|
+
],
|
|
172
|
+
"action": {
|
|
173
|
+
"mitigate": {
|
|
174
|
+
"action": "rate_limit",
|
|
175
|
+
"rateLimit": {
|
|
176
|
+
"requests": 100,
|
|
177
|
+
"window": "1m",
|
|
178
|
+
"characteristics": ["ip.src"]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"ips": [
|
|
185
|
+
{ "ip": "203.0.113.0/24", "action": "deny", "notes": "Known attack subnet" }
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
```
|