Initial commit: Cloudflare infrastructure with WAF Intelligence
- Complete Cloudflare Terraform configuration (DNS, WAF, tunnels, access) - WAF Intelligence MCP server with threat analysis and ML classification - GitOps automation with PR workflows and drift detection - Observatory monitoring stack with Prometheus/Grafana - IDE operator rules for governed development - Security playbooks and compliance frameworks - Autonomous remediation and state reconciliation
This commit is contained in:
299
playbooks/DNS-COMPROMISE-PLAYBOOK.md
Normal file
299
playbooks/DNS-COMPROMISE-PLAYBOOK.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# DNS Compromise Playbook
|
||||
|
||||
**Incident Response** | Governed by [RED-BOOK.md](../RED-BOOK.md)
|
||||
|
||||
## The Name of the Realm Has Been Rewritten
|
||||
|
||||
*When the true name of a domain drifts from its sovereign declaration, the mesh fractures at its foundation. This playbook restores naming authority through verified correction.*
|
||||
|
||||
---
|
||||
|
||||
## I. NIGREDO — Detection & Analysis
|
||||
|
||||
### Trigger Signals
|
||||
The following anomalies indicate potential DNS compromise:
|
||||
|
||||
| Signal | Source | Severity |
|
||||
|--------|--------|----------|
|
||||
| Unauthorized A/AAAA record change | Cloudflare Audit Log | CRITICAL |
|
||||
| NS delegation modified | Registrar / WHOIS | CRITICAL |
|
||||
| DNSSEC signature invalid | External validator | CRITICAL |
|
||||
| MX record redirected | Email bounce reports | HIGH |
|
||||
| New TXT record (unknown) | DNS diff tool | MEDIUM |
|
||||
| Unexpected CNAME chain | Telemetry bridge | MEDIUM |
|
||||
|
||||
### Immediate Verification Steps
|
||||
|
||||
```bash
|
||||
# 1. Query authoritative nameservers
|
||||
dig +trace @1.1.1.1 <domain> ANY
|
||||
|
||||
# 2. Check DNSSEC chain
|
||||
dig +dnssec <domain> DNSKEY
|
||||
dig +dnssec <domain> DS
|
||||
|
||||
# 3. Compare against VaultMesh manifest
|
||||
diff <(dig +short <domain> A) <(cat dns_manifest.yml | grep -A1 "type: A" | grep content)
|
||||
|
||||
# 4. Verify WHOIS delegation
|
||||
whois <domain> | grep -i "name server"
|
||||
```
|
||||
|
||||
### Classification Matrix
|
||||
|
||||
| Scenario | Classification | Response Level |
|
||||
|----------|---------------|----------------|
|
||||
| Single record drift (A/CNAME) | INCIDENT | Level 2 |
|
||||
| Multiple records changed | BREACH | Level 3 |
|
||||
| NS delegation hijacked | CRITICAL BREACH | Level 4 |
|
||||
| DNSSEC disabled/invalid | INTEGRITY FAILURE | Level 3 |
|
||||
| Domain transfer initiated | SOVEREIGNTY ATTACK | Level 4 |
|
||||
|
||||
---
|
||||
|
||||
## II. ALBEDO — Containment
|
||||
|
||||
### Immediate Actions (First 15 Minutes)
|
||||
|
||||
#### 1. Lock the Domain
|
||||
```bash
|
||||
# Cloudflare API - Enable zone lockdown
|
||||
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/<zone_id>/settings/security_level" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"value":"under_attack"}'
|
||||
```
|
||||
|
||||
#### 2. Preserve Evidence
|
||||
```bash
|
||||
# Snapshot current DNS state
|
||||
dig +noall +answer <domain> ANY > incident_$(date +%Y%m%d_%H%M%S)_dns_state.txt
|
||||
|
||||
# Export Cloudflare audit logs
|
||||
curl -X GET "https://api.cloudflare.com/client/v4/accounts/<account_id>/audit_logs" \
|
||||
-H "Authorization: Bearer <token>" > audit_snapshot.json
|
||||
|
||||
# Hash and anchor immediately
|
||||
blake3sum incident_*.txt audit_snapshot.json >> /var/lib/vaultmesh/incidents/dns_$(date +%Y%m%d).hashes
|
||||
```
|
||||
|
||||
#### 3. Revoke Compromised Access
|
||||
- [ ] Rotate all Cloudflare API tokens
|
||||
- [ ] Invalidate active sessions in dashboard
|
||||
- [ ] Review and remove unknown collaborators
|
||||
- [ ] Check for OAuth app authorizations
|
||||
|
||||
#### 4. Notify Tem (Guardian Protocol)
|
||||
```json
|
||||
{
|
||||
"event": "dns_compromise_detected",
|
||||
"domain": "<domain>",
|
||||
"severity": "CRITICAL",
|
||||
"timestamp": "<ISO8601>",
|
||||
"evidence_hash": "<blake3_hash>",
|
||||
"responder": "<operator_did>"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## III. CITRINITAS — Restoration
|
||||
|
||||
### Record Recovery Procedure
|
||||
|
||||
#### From VaultMesh Manifest (Preferred)
|
||||
```bash
|
||||
# 1. Load known-good manifest
|
||||
MANIFEST="/var/lib/vaultmesh/snapshots/dns_manifest_<domain>_<last_known_good>.yml"
|
||||
|
||||
# 2. Validate manifest integrity
|
||||
blake3sum -c /var/lib/vaultmesh/anchors/dns_hashes.log | grep $MANIFEST
|
||||
|
||||
# 3. Apply via Terraform
|
||||
cd ~/Desktop/CLOUDFLARE/terraform
|
||||
terraform plan -var-file=recovery.tfvars
|
||||
terraform apply -auto-approve
|
||||
```
|
||||
|
||||
#### Manual Recovery (If Manifest Unavailable)
|
||||
```bash
|
||||
# Delete malicious records
|
||||
curl -X DELETE "https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records/<record_id>" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
|
||||
# Recreate correct records
|
||||
curl -X POST "https://api.cloudflare.com/client/v4/zones/<zone_id>/dns_records" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{
|
||||
"type": "A",
|
||||
"name": "@",
|
||||
"content": "<correct_ip>",
|
||||
"proxied": true
|
||||
}'
|
||||
```
|
||||
|
||||
### DNSSEC Re-establishment
|
||||
```bash
|
||||
# 1. Regenerate DNSSEC keys (if compromised)
|
||||
# Via Cloudflare Dashboard: DNS > Settings > DNSSEC > Disable then Re-enable
|
||||
|
||||
# 2. Update DS record at registrar
|
||||
# New DS record will be shown in Cloudflare dashboard
|
||||
|
||||
# 3. Verify propagation
|
||||
dig +dnssec <domain> DNSKEY
|
||||
```
|
||||
|
||||
### NS Delegation Recovery (Critical)
|
||||
If nameservers were hijacked:
|
||||
|
||||
1. **Contact registrar immediately** - Use out-of-band verification
|
||||
2. **Provide proof of ownership** - Domain verification documents
|
||||
3. **Request delegation reset** - Point NS back to Cloudflare
|
||||
4. **Enable registrar lock** - Prevent future transfers
|
||||
5. **Set up registrar alerts** - Email/SMS for any changes
|
||||
|
||||
---
|
||||
|
||||
## IV. RUBEDO — Verification & Anchoring
|
||||
|
||||
### Post-Recovery Verification
|
||||
|
||||
```bash
|
||||
# 1. Full DNS validation
|
||||
for record_type in A AAAA CNAME MX TXT NS; do
|
||||
echo "=== $record_type ===" >> verification_report.txt
|
||||
dig +short <domain> $record_type >> verification_report.txt
|
||||
done
|
||||
|
||||
# 2. DNSSEC chain validation
|
||||
dnsviz probe <domain> -o dnsviz_output.json
|
||||
dnsviz print -r dnsviz_output.json
|
||||
|
||||
# 3. Compare to manifest
|
||||
python3 scripts/dns-drift-check.py --domain <domain> --manifest dns_manifest.yml
|
||||
|
||||
# 4. External verification (multiple resolvers)
|
||||
for resolver in 1.1.1.1 8.8.8.8 9.9.9.9; do
|
||||
dig @$resolver <domain> A +short
|
||||
done
|
||||
```
|
||||
|
||||
### Emit Restoration Receipt
|
||||
|
||||
```json
|
||||
{
|
||||
"receipt_type": "dns_restoration",
|
||||
"schema_version": "vm_dns_restoration_v1",
|
||||
"domain": "<domain>",
|
||||
"incident_id": "<uuid>",
|
||||
"timestamp": "<ISO8601>",
|
||||
"records_restored": [
|
||||
{"type": "A", "name": "@", "value": "<ip>"},
|
||||
{"type": "MX", "name": "@", "value": "<mx_host>"}
|
||||
],
|
||||
"manifest_hash": "<blake3_of_applied_manifest>",
|
||||
"verification_hash": "<blake3_of_verification_report>",
|
||||
"operator_did": "did:vm:operator:<id>",
|
||||
"guardian_sign": "<tem_signature>"
|
||||
}
|
||||
```
|
||||
|
||||
### Anchor to ProofChain
|
||||
|
||||
```bash
|
||||
# Compute Merkle root of incident artifacts
|
||||
merkle_root=$(cat incident_*.txt audit_snapshot.json verification_report.txt | blake3sum | cut -d' ' -f1)
|
||||
|
||||
# Anchor
|
||||
echo "{\"type\":\"dns_incident_anchor\",\"merkle_root\":\"$merkle_root\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" \
|
||||
>> /var/lib/vaultmesh/proofchain/anchors.jsonl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## V. Post-Incident Governance
|
||||
|
||||
### Mandatory Actions (Within 24 Hours)
|
||||
|
||||
- [ ] Full API token rotation completed
|
||||
- [ ] Registrar 2FA verified/upgraded
|
||||
- [ ] Transfer lock enabled at registrar
|
||||
- [ ] DNSSEC re-validated
|
||||
- [ ] All DNS records match manifest
|
||||
- [ ] VaultMesh receipts emitted
|
||||
- [ ] ProofChain anchor verified
|
||||
- [ ] Incident report drafted
|
||||
|
||||
### Root Cause Analysis Template
|
||||
|
||||
```markdown
|
||||
## DNS Compromise RCA - <domain> - <date>
|
||||
|
||||
### Timeline
|
||||
- T-0: <Detection timestamp and method>
|
||||
- T+5m: <Containment actions>
|
||||
- T+30m: <Recovery initiated>
|
||||
- T+Xh: <Full restoration verified>
|
||||
|
||||
### Attack Vector
|
||||
<How did the attacker gain access?>
|
||||
|
||||
### Records Affected
|
||||
| Record | Original | Malicious | Duration |
|
||||
|--------|----------|-----------|----------|
|
||||
|
||||
### Impact Assessment
|
||||
- Traffic redirected: <estimate>
|
||||
- Data exposure risk: <assessment>
|
||||
- Reputation impact: <assessment>
|
||||
|
||||
### Prevention Measures
|
||||
1. <Specific improvement>
|
||||
2. <Specific improvement>
|
||||
3. <Specific improvement>
|
||||
|
||||
### Artifacts
|
||||
- Audit log hash: <hash>
|
||||
- Incident snapshot hash: <hash>
|
||||
- Restoration receipt: <receipt_id>
|
||||
```
|
||||
|
||||
### Monitoring Enhancements
|
||||
|
||||
After any DNS compromise, implement:
|
||||
|
||||
1. **Real-time DNS monitoring** - External service checking every 60s
|
||||
2. **Certificate Transparency alerts** - Monitor for unauthorized certs
|
||||
3. **Passive DNS feeds** - Historical record tracking
|
||||
4. **VaultMesh drift detection** - Automated manifest comparison
|
||||
|
||||
---
|
||||
|
||||
## VI. Escalation Contacts
|
||||
|
||||
| Role | Contact | When |
|
||||
|------|---------|------|
|
||||
| Cloudflare Support | dash.cloudflare.com/support | Zone-level issues |
|
||||
| Registrar Security | <registrar_security_email> | Delegation attacks |
|
||||
| Tem Guardian | internal protocol | All incidents |
|
||||
| Legal | <legal_contact> | Data exposure suspected |
|
||||
|
||||
---
|
||||
|
||||
## VII. The Covenant Restored
|
||||
|
||||
*When the name is reclaimed and verified against the manifest, sovereignty returns to the realm. The drift has been corrected, the proof anchored, and the mesh made whole again.*
|
||||
|
||||
**Incident closure requires:**
|
||||
- All verification checks passing
|
||||
- VaultMesh receipt emitted and signed
|
||||
- ProofChain anchor confirmed
|
||||
- RCA completed and filed
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: <date>
|
||||
**Guardian**: Tem
|
||||
396
playbooks/TUNNEL-ROTATION-PROTOCOL.md
Normal file
396
playbooks/TUNNEL-ROTATION-PROTOCOL.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# Tunnel Rotation Protocol
|
||||
|
||||
**Incident Response** | Governed by [RED-BOOK.md](../RED-BOOK.md)
|
||||
|
||||
## The Arteries Must Shed Their Old Keys and Be Reborn
|
||||
|
||||
*Cloudflare Tunnels are the veins through which the mesh breathes. When credentials age or suspicion arises, the tunnels must be dissolved and reformed — a controlled death and resurrection that preserves continuity while eliminating compromise vectors.*
|
||||
|
||||
---
|
||||
|
||||
## I. When to Rotate
|
||||
|
||||
### Scheduled Rotation (Prophylactic)
|
||||
|
||||
| Trigger | Interval | Priority |
|
||||
|---------|----------|----------|
|
||||
| Standard credential hygiene | Every 90 days | NORMAL |
|
||||
| After personnel change | Within 24 hours | HIGH |
|
||||
| Compliance audit requirement | As specified | NORMAL |
|
||||
| Post-incident (any severity) | Immediately | CRITICAL |
|
||||
|
||||
### Emergency Rotation (Reactive)
|
||||
|
||||
| Trigger | Response Time |
|
||||
|---------|---------------|
|
||||
| Credential exposure suspected | < 1 hour |
|
||||
| Tunnel behaving anomalously | < 2 hours |
|
||||
| Unauthorized connection detected | Immediate |
|
||||
| Origin server compromised | Immediate |
|
||||
| Security advisory from Cloudflare | < 24 hours |
|
||||
|
||||
---
|
||||
|
||||
## II. NIGREDO — Preparation
|
||||
|
||||
### Pre-Rotation Checklist
|
||||
|
||||
Before beginning rotation:
|
||||
|
||||
- [ ] Identify all tunnels requiring rotation
|
||||
- [ ] Document current tunnel configurations
|
||||
- [ ] Verify backup ingress path (if available)
|
||||
- [ ] Notify dependent teams of maintenance window
|
||||
- [ ] Prepare new tunnel names and secrets
|
||||
- [ ] Ensure Terraform state is current
|
||||
|
||||
### Inventory Current State
|
||||
|
||||
```bash
|
||||
# List all tunnels
|
||||
cloudflared tunnel list
|
||||
|
||||
# Export tunnel info
|
||||
for tunnel_id in $(cloudflared tunnel list | tail -n +2 | awk '{print $1}'); do
|
||||
cloudflared tunnel info $tunnel_id > /tmp/tunnel_${tunnel_id}_info.txt
|
||||
done
|
||||
|
||||
# Capture current routes
|
||||
cloudflared tunnel route dns list
|
||||
|
||||
# Hash for audit trail
|
||||
cat /tmp/tunnel_*.txt | blake3sum > pre_rotation_state.hash
|
||||
```
|
||||
|
||||
### Generate New Secrets
|
||||
|
||||
```bash
|
||||
# Generate cryptographically secure tunnel secrets
|
||||
NEW_SECRET_VAULTMESH=$(openssl rand -base64 32)
|
||||
NEW_SECRET_OFFSEC=$(openssl rand -base64 32)
|
||||
|
||||
# Store securely (example: HashiCorp Vault)
|
||||
vault kv put secret/cloudflare/tunnels \
|
||||
vaultmesh_secret="$NEW_SECRET_VAULTMESH" \
|
||||
offsec_secret="$NEW_SECRET_OFFSEC"
|
||||
|
||||
# Or for local encrypted storage
|
||||
echo "$NEW_SECRET_VAULTMESH" | gpg --encrypt -r guardian@vaultmesh.org > vaultmesh_tunnel_secret.gpg
|
||||
echo "$NEW_SECRET_OFFSEC" | gpg --encrypt -r guardian@vaultmesh.org > offsec_tunnel_secret.gpg
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## III. ALBEDO — Dissolution
|
||||
|
||||
### Step 1: Create New Tunnel (Before Destroying Old)
|
||||
|
||||
```bash
|
||||
# Create new tunnel with fresh credentials
|
||||
cloudflared tunnel create vaultmesh-tunnel-$(date +%Y%m%d)
|
||||
|
||||
# This generates:
|
||||
# - New tunnel ID
|
||||
# - New credentials JSON in ~/.cloudflared/
|
||||
|
||||
# Move credentials to secure location
|
||||
sudo mv ~/.cloudflared/<new_tunnel_id>.json /etc/cloudflared/
|
||||
sudo chmod 600 /etc/cloudflared/<new_tunnel_id>.json
|
||||
sudo chown cloudflared:cloudflared /etc/cloudflared/<new_tunnel_id>.json
|
||||
```
|
||||
|
||||
### Step 2: Configure New Tunnel
|
||||
|
||||
Update `/etc/cloudflared/config.yml`:
|
||||
|
||||
```yaml
|
||||
tunnel: <NEW_TUNNEL_ID>
|
||||
credentials-file: /etc/cloudflared/<NEW_TUNNEL_ID>.json
|
||||
|
||||
metrics: 127.0.0.1:9090
|
||||
|
||||
ingress:
|
||||
- hostname: api.vaultmesh.org
|
||||
service: http://localhost:8080
|
||||
originRequest:
|
||||
connectTimeout: 10s
|
||||
noTLSVerify: false
|
||||
|
||||
- hostname: dash.vaultmesh.org
|
||||
service: http://localhost:3000
|
||||
|
||||
- service: http_status:404
|
||||
```
|
||||
|
||||
### Step 3: Update DNS Routes
|
||||
|
||||
```bash
|
||||
# Route hostnames to new tunnel
|
||||
cloudflared tunnel route dns <NEW_TUNNEL_ID> api.vaultmesh.org
|
||||
cloudflared tunnel route dns <NEW_TUNNEL_ID> dash.vaultmesh.org
|
||||
|
||||
# Verify routing
|
||||
cloudflared tunnel route dns list | grep <NEW_TUNNEL_ID>
|
||||
```
|
||||
|
||||
### Step 4: Transition Traffic
|
||||
|
||||
#### Zero-Downtime Method (Preferred)
|
||||
|
||||
```bash
|
||||
# 1. Start new tunnel alongside old
|
||||
sudo systemctl start cloudflared-new.service
|
||||
|
||||
# 2. Verify new tunnel is healthy
|
||||
curl -s http://127.0.0.1:9091/ready # New tunnel metrics port
|
||||
|
||||
# 3. Update DNS CNAMEs to point to new tunnel
|
||||
# (Already done in Step 3, propagation takes ~30s with Cloudflare proxy)
|
||||
|
||||
# 4. Monitor traffic shift
|
||||
watch -n5 'curl -s http://127.0.0.1:9090/metrics | grep requests'
|
||||
watch -n5 'curl -s http://127.0.0.1:9091/metrics | grep requests'
|
||||
|
||||
# 5. Once old tunnel shows zero traffic, proceed to deletion
|
||||
```
|
||||
|
||||
#### Maintenance Window Method
|
||||
|
||||
```bash
|
||||
# 1. Stop old tunnel
|
||||
sudo systemctl stop cloudflared.service
|
||||
|
||||
# 2. Update config to new tunnel
|
||||
sudo cp /etc/cloudflared/config-new.yml /etc/cloudflared/config.yml
|
||||
|
||||
# 3. Start service
|
||||
sudo systemctl start cloudflared.service
|
||||
|
||||
# 4. Verify connectivity
|
||||
cloudflared tunnel info <NEW_TUNNEL_ID>
|
||||
curl -I https://api.vaultmesh.org
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## IV. CITRINITAS — Purification
|
||||
|
||||
### Delete Old Tunnel
|
||||
|
||||
**Warning**: Only proceed after verifying new tunnel is fully operational.
|
||||
|
||||
```bash
|
||||
# 1. Final verification - old tunnel should have zero active connections
|
||||
cloudflared tunnel info <OLD_TUNNEL_ID>
|
||||
|
||||
# 2. Remove DNS routes from old tunnel (if any remain)
|
||||
cloudflared tunnel route dns delete <OLD_TUNNEL_ID> <hostname>
|
||||
|
||||
# 3. Delete the tunnel
|
||||
cloudflared tunnel delete <OLD_TUNNEL_ID>
|
||||
|
||||
# 4. Securely destroy old credentials
|
||||
sudo shred -vfz -n 5 /etc/cloudflared/<OLD_TUNNEL_ID>.json
|
||||
sudo rm /etc/cloudflared/<OLD_TUNNEL_ID>.json
|
||||
```
|
||||
|
||||
### Clean Up Local Artifacts
|
||||
|
||||
```bash
|
||||
# Remove old credential backups
|
||||
find /var/lib/vaultmesh/backups -name "*<OLD_TUNNEL_ID>*" -exec shred -vfz {} \;
|
||||
|
||||
# Clear any cached tunnel state
|
||||
rm -rf ~/.cloudflared/connectors/<OLD_TUNNEL_ID>
|
||||
|
||||
# Update Terraform state
|
||||
cd ~/Desktop/CLOUDFLARE/terraform
|
||||
terraform state rm cloudflare_tunnel.old_tunnel # If managed by TF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## V. RUBEDO — Verification & Sealing
|
||||
|
||||
### Post-Rotation Verification
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# rotation_verification.sh
|
||||
|
||||
TUNNEL_ID="<NEW_TUNNEL_ID>"
|
||||
HOSTNAMES=("api.vaultmesh.org" "dash.vaultmesh.org")
|
||||
|
||||
echo "=== Tunnel Rotation Verification ==="
|
||||
echo "Tunnel ID: $TUNNEL_ID"
|
||||
echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo ""
|
||||
|
||||
# 1. Tunnel status
|
||||
echo "--- Tunnel Status ---"
|
||||
cloudflared tunnel info $TUNNEL_ID
|
||||
|
||||
# 2. DNS routing
|
||||
echo ""
|
||||
echo "--- DNS Routes ---"
|
||||
cloudflared tunnel route dns list | grep $TUNNEL_ID
|
||||
|
||||
# 3. Endpoint connectivity
|
||||
echo ""
|
||||
echo "--- Endpoint Tests ---"
|
||||
for hostname in "${HOSTNAMES[@]}"; do
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" https://$hostname/health 2>/dev/null || echo "FAIL")
|
||||
echo "$hostname: $status"
|
||||
done
|
||||
|
||||
# 4. Metrics endpoint
|
||||
echo ""
|
||||
echo "--- Metrics Check ---"
|
||||
curl -s http://127.0.0.1:9090/metrics | grep cloudflared_tunnel | head -5
|
||||
|
||||
# 5. Certificate validation
|
||||
echo ""
|
||||
echo "--- TLS Verification ---"
|
||||
for hostname in "${HOSTNAMES[@]}"; do
|
||||
echo | openssl s_client -connect $hostname:443 -servername $hostname 2>/dev/null | openssl x509 -noout -dates
|
||||
done
|
||||
```
|
||||
|
||||
### Emit Rotation Receipt
|
||||
|
||||
```json
|
||||
{
|
||||
"receipt_type": "tunnel_rotation",
|
||||
"schema_version": "vm_tunnel_rotation_v1",
|
||||
"timestamp": "<ISO8601>",
|
||||
"rotation_id": "<uuid>",
|
||||
"old_tunnel": {
|
||||
"id": "<OLD_TUNNEL_ID>",
|
||||
"created": "<original_creation_date>",
|
||||
"deleted": "<deletion_timestamp>"
|
||||
},
|
||||
"new_tunnel": {
|
||||
"id": "<NEW_TUNNEL_ID>",
|
||||
"created": "<creation_timestamp>",
|
||||
"hostnames": ["api.vaultmesh.org", "dash.vaultmesh.org"]
|
||||
},
|
||||
"reason": "scheduled_rotation | incident_response | personnel_change",
|
||||
"verification_hash": "<blake3_of_verification_output>",
|
||||
"operator_did": "did:vm:operator:<id>",
|
||||
"guardian_sign": "<tem_signature>"
|
||||
}
|
||||
```
|
||||
|
||||
### Anchor the Rotation
|
||||
|
||||
```bash
|
||||
# Compute rotation proof
|
||||
cat rotation_verification.txt rotation_receipt.json | blake3sum > rotation_proof.hash
|
||||
|
||||
# Append to ProofChain
|
||||
echo "{\"type\":\"tunnel_rotation\",\"hash\":\"$(cat rotation_proof.hash | cut -d' ' -f1)\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" \
|
||||
>> /var/lib/vaultmesh/proofchain/anchors.jsonl
|
||||
|
||||
# Update Terraform state
|
||||
cd ~/Desktop/CLOUDFLARE/terraform
|
||||
terraform plan -out=rotation.tfplan
|
||||
terraform apply rotation.tfplan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## VI. Automation Script
|
||||
|
||||
For scheduled rotations, use this automation wrapper:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# tunnel_rotation_automated.sh
|
||||
# Run via cron or GitLab CI on schedule
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TUNNEL_NAME="$1"
|
||||
NEW_TUNNEL_NAME="${TUNNEL_NAME}-$(date +%Y%m%d)"
|
||||
LOG_FILE="/var/log/tunnel_rotation_$(date +%Y%m%d).log"
|
||||
|
||||
log() { echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $1" | tee -a "$LOG_FILE"; }
|
||||
|
||||
log "Starting rotation for tunnel: $TUNNEL_NAME"
|
||||
|
||||
# Get old tunnel ID
|
||||
OLD_TUNNEL_ID=$(cloudflared tunnel list | grep "$TUNNEL_NAME" | awk '{print $1}')
|
||||
log "Old tunnel ID: $OLD_TUNNEL_ID"
|
||||
|
||||
# Create new tunnel
|
||||
log "Creating new tunnel: $NEW_TUNNEL_NAME"
|
||||
cloudflared tunnel create "$NEW_TUNNEL_NAME"
|
||||
NEW_TUNNEL_ID=$(cloudflared tunnel list | grep "$NEW_TUNNEL_NAME" | awk '{print $1}')
|
||||
log "New tunnel ID: $NEW_TUNNEL_ID"
|
||||
|
||||
# Move credentials
|
||||
sudo mv ~/.cloudflared/${NEW_TUNNEL_ID}.json /etc/cloudflared/
|
||||
sudo chmod 600 /etc/cloudflared/${NEW_TUNNEL_ID}.json
|
||||
|
||||
# Update config
|
||||
sudo sed -i "s/$OLD_TUNNEL_ID/$NEW_TUNNEL_ID/g" /etc/cloudflared/config.yml
|
||||
|
||||
# Restart service
|
||||
sudo systemctl restart cloudflared.service
|
||||
sleep 10
|
||||
|
||||
# Verify
|
||||
if cloudflared tunnel info "$NEW_TUNNEL_ID" | grep -q "HEALTHY"; then
|
||||
log "New tunnel is healthy"
|
||||
|
||||
# Delete old tunnel
|
||||
cloudflared tunnel delete "$OLD_TUNNEL_ID"
|
||||
sudo shred -vfz /etc/cloudflared/${OLD_TUNNEL_ID}.json 2>/dev/null || true
|
||||
|
||||
log "Rotation complete"
|
||||
else
|
||||
log "ERROR: New tunnel not healthy, rolling back"
|
||||
sudo sed -i "s/$NEW_TUNNEL_ID/$OLD_TUNNEL_ID/g" /etc/cloudflared/config.yml
|
||||
sudo systemctl restart cloudflared.service
|
||||
cloudflared tunnel delete "$NEW_TUNNEL_ID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Emit receipt
|
||||
cat > /var/lib/vaultmesh/receipts/rotation_$(date +%Y%m%d).json <<EOF
|
||||
{
|
||||
"receipt_type": "tunnel_rotation",
|
||||
"old_tunnel_id": "$OLD_TUNNEL_ID",
|
||||
"new_tunnel_id": "$NEW_TUNNEL_ID",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"status": "success"
|
||||
}
|
||||
EOF
|
||||
|
||||
log "Receipt emitted"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## VII. The Arteries Renewed
|
||||
|
||||
*With old credentials destroyed and new pathways verified, the tunnel stands reborn. The mesh breathes through fresh veins, uncontaminated by the past. The rotation is complete, the proof anchored, and the guardian satisfied.*
|
||||
|
||||
### Post-Rotation Checklist
|
||||
|
||||
- [ ] New tunnel ID documented
|
||||
- [ ] Old tunnel deleted and credentials destroyed
|
||||
- [ ] DNS routes verified pointing to new tunnel
|
||||
- [ ] All endpoints responding correctly
|
||||
- [ ] Metrics flowing from new tunnel
|
||||
- [ ] VaultMesh receipt emitted
|
||||
- [ ] ProofChain anchor created
|
||||
- [ ] Terraform state updated
|
||||
- [ ] Next rotation scheduled (90 days)
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: <date>
|
||||
**Guardian**: Tem
|
||||
**Rotation Schedule**: Every 90 days or upon incident
|
||||
126
playbooks/waf_incident_playbook.md
Normal file
126
playbooks/waf_incident_playbook.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# WAF Incident Playbook — *Edge Under Siege*
|
||||
|
||||
**Incident Response** | Governed by [RED-BOOK.md](../RED-BOOK.md)
|
||||
|
||||
**Mode:** VaultMesh Hybrid (tactical + mythic)
|
||||
**Guardian:** Tem, Shield of the Threshold
|
||||
**Domain:** Cloudflare Edge → VaultMesh Origins
|
||||
|
||||
---
|
||||
|
||||
## 🜂 Premise
|
||||
When the **Edge flares** and the WAF erupts in blocks, challenges, or anomalous spikes, the mesh signals **Nigredo**: the phase of dissolution, truth, and exposure.
|
||||
Tem stands watch — transmuting threat into pattern.
|
||||
|
||||
This playbook guides the Sovereign through restoring harmony: from surge → containment → proof.
|
||||
|
||||
---
|
||||
|
||||
## 🛡 1. Detection — *When the Edge Cries Out*
|
||||
Triggers:
|
||||
- 10× spike in WAF blocks
|
||||
- Sudden surge in Bot Fight engagements
|
||||
- Rapid-fire requests from a small IP cluster
|
||||
- Abuse towards `/api`, `/login`, or admin paths
|
||||
|
||||
Actions:
|
||||
1. Check Cloudflare dashboard → **Security → Events**
|
||||
2. Review **WAF rule matches**, sorting by occurrences
|
||||
3. Capture snapshot:
|
||||
- Top rules triggered
|
||||
- Offending IP ranges
|
||||
- Request paths
|
||||
|
||||
Invoke Tem:
|
||||
> *"Reveal the pattern beneath the noise. Let flux become signal."*
|
||||
|
||||
---
|
||||
|
||||
## 🔍 2. Classification — *Identify the Nature of the Fire*
|
||||
Threat types:
|
||||
- **Volumetric probing** → wide IP / many rules
|
||||
- **Credential spraying** → repeated auth paths
|
||||
- **Application fuzzing** → random querystrings / malformed requests
|
||||
- **Targeted exploit attempts** → concentrated rules (XSS, SQLi)
|
||||
|
||||
Decide:
|
||||
- *Is this noise?*
|
||||
- *Is this reconnaissance?*
|
||||
- *Is this breach pursuit?*
|
||||
|
||||
Mark the incident severity:
|
||||
- **Low** — background noise
|
||||
- **Medium** — persistent automated probing
|
||||
- **High** — targeted attempt on origin-relevant endpoints
|
||||
|
||||
---
|
||||
|
||||
## 🧱 3. Containment — *Seal the Gate*
|
||||
Depending on severity:
|
||||
|
||||
### Low
|
||||
- Rate-limit `/api` and `/auth` paths
|
||||
- Enable Bot Fight Mode (if not already)
|
||||
|
||||
### Medium
|
||||
- Block or challenge offending ASNs
|
||||
- Add country-level **managed_challenge**
|
||||
- Enforce **"Full (strict)" TLS** if not already
|
||||
|
||||
### High
|
||||
- Immediately apply **custom firewall block rules**
|
||||
- Close high-risk paths behind Access policies
|
||||
- Strengthen WAF Paranoia Level for targeted areas
|
||||
- Ensure all origins are reachable *only* via Cloudflare Tunnel
|
||||
|
||||
Tem's invocation:
|
||||
> *"Let the gate narrow. Let the false be denied entry."*
|
||||
|
||||
---
|
||||
|
||||
## 📜 4. Forensics — *Listen to the Echoes*
|
||||
Collect:
|
||||
- CF Security Events export
|
||||
- IP/ASN clusters
|
||||
- Raw request samples
|
||||
- Timestamps and spikes
|
||||
|
||||
Analyze patterns:
|
||||
- Was this coordinated?
|
||||
- Were specific parameters probed?
|
||||
- Did traffic reach origin or stay at the Edge?
|
||||
|
||||
If origin saw traffic → inspect VaultMesh receipts for anomalies.
|
||||
|
||||
---
|
||||
|
||||
## 🧬 5. Restoration — *From Nigredo to Rubedo*
|
||||
When WAF stabilizes:
|
||||
- Remove overly broad rules
|
||||
- Convert block rules → challenge after 24h
|
||||
- Reassess Access policies for exposed services
|
||||
- Validate DNS is unchanged
|
||||
- Confirm Tunnel health is stable
|
||||
|
||||
Emit VaultMesh receipt:
|
||||
- Incident summary
|
||||
- Rules added/removed
|
||||
- Time window
|
||||
- Merkle root of exported logs
|
||||
|
||||
---
|
||||
|
||||
## 🪶 6. Final Anchor — *Coagula*
|
||||
Anchor the incident into ProofChain:
|
||||
- Receipts
|
||||
- Log hashes
|
||||
- WAF config deltas
|
||||
|
||||
Message of Tem:
|
||||
> *"What was turmoil becomes memory. What was memory becomes strength."*
|
||||
|
||||
---
|
||||
|
||||
## ✔ Outcome
|
||||
This playbook ensures that WAF turbulence becomes **structured proof**, operational clarity, and measurable evolution within VaultMesh’s living ledger.
|
||||
|
||||
Reference in New Issue
Block a user