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:
209
scripts/anchor-cloudflare-state.sh
Executable file
209
scripts/anchor-cloudflare-state.sh
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Cloudflare State Anchor
|
||||
# Orchestrates state reconciliation, invariant checking, and ProofChain anchoring.
|
||||
#
|
||||
# Usage:
|
||||
# ./anchor-cloudflare-state.sh [--zone-id ZONE_ID] [--account-id ACCOUNT_ID]
|
||||
#
|
||||
# Environment Variables:
|
||||
# CLOUDFLARE_API_TOKEN - Required
|
||||
# CLOUDFLARE_ZONE_ID - Zone ID (or use --zone-id)
|
||||
# CLOUDFLARE_ACCOUNT_ID - Account ID (or use --account-id)
|
||||
# VAULTMESH_ANCHORS_PATH - Path to ProofChain anchors file (optional)
|
||||
#
|
||||
# Exit Codes:
|
||||
# 0 - Success, all invariants passed
|
||||
# 1 - Success, but invariants failed (anomalies detected)
|
||||
# 2 - Error during execution
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BASE_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
SNAPSHOTS_DIR="${BASE_DIR}/snapshots"
|
||||
RECEIPTS_DIR="${BASE_DIR}/receipts"
|
||||
ANOMALIES_DIR="${BASE_DIR}/anomalies"
|
||||
ANCHORS_PATH="${VAULTMESH_ANCHORS_PATH:-${BASE_DIR}/proofchain-anchors.jsonl}"
|
||||
|
||||
# Parse arguments
|
||||
ZONE_ID="${CLOUDFLARE_ZONE_ID:-}"
|
||||
ACCOUNT_ID="${CLOUDFLARE_ACCOUNT_ID:-}"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--zone-id)
|
||||
ZONE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--account-id)
|
||||
ACCOUNT_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate
|
||||
if [[ -z "${CLOUDFLARE_API_TOKEN:-}" ]]; then
|
||||
echo "Error: CLOUDFLARE_API_TOKEN environment variable required"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ -z "$ZONE_ID" ]]; then
|
||||
echo "Error: Zone ID required (--zone-id or CLOUDFLARE_ZONE_ID)"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ -z "$ACCOUNT_ID" ]]; then
|
||||
echo "Error: Account ID required (--account-id or CLOUDFLARE_ACCOUNT_ID)"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$SNAPSHOTS_DIR" "$RECEIPTS_DIR" "$ANOMALIES_DIR"
|
||||
|
||||
# Timestamp for this run
|
||||
TIMESTAMP=$(date -u +%Y-%m-%dT%H-%M-%SZ)
|
||||
|
||||
echo "======================================"
|
||||
echo "Cloudflare State Anchor"
|
||||
echo "======================================"
|
||||
echo "Timestamp: $TIMESTAMP"
|
||||
echo "Zone ID: $ZONE_ID"
|
||||
echo "Account ID: $ACCOUNT_ID"
|
||||
echo ""
|
||||
|
||||
# Step 1: Run State Reconciler
|
||||
echo ">>> Step 1: Fetching Cloudflare state..."
|
||||
python3 "${SCRIPT_DIR}/state-reconciler.py" \
|
||||
--zone-id "$ZONE_ID" \
|
||||
--account-id "$ACCOUNT_ID" \
|
||||
--output-dir "$SNAPSHOTS_DIR" \
|
||||
--receipt-dir "$RECEIPTS_DIR"
|
||||
|
||||
# Find the latest snapshot
|
||||
LATEST_SNAPSHOT=$(ls -t "${SNAPSHOTS_DIR}"/cloudflare-*.json 2>/dev/null | head -1)
|
||||
if [[ -z "$LATEST_SNAPSHOT" ]]; then
|
||||
echo "Error: No snapshot found"
|
||||
exit 2
|
||||
fi
|
||||
echo "Snapshot: $LATEST_SNAPSHOT"
|
||||
|
||||
# Extract Merkle root from snapshot
|
||||
MERKLE_ROOT=$(python3 -c "
|
||||
import json
|
||||
with open('$LATEST_SNAPSHOT') as f:
|
||||
data = json.load(f)
|
||||
print(data['integrity']['merkle_root'])
|
||||
")
|
||||
echo "Merkle Root: $MERKLE_ROOT"
|
||||
echo ""
|
||||
|
||||
# Step 2: Run Invariant Checker
|
||||
echo ">>> Step 2: Checking invariants..."
|
||||
INVARIANT_EXIT=0
|
||||
python3 "${SCRIPT_DIR}/invariant-checker.py" \
|
||||
--snapshot "$LATEST_SNAPSHOT" \
|
||||
--output-dir "$ANOMALIES_DIR" || INVARIANT_EXIT=$?
|
||||
|
||||
# Find latest report
|
||||
LATEST_REPORT=$(ls -t "${ANOMALIES_DIR}"/invariant-report-*.json 2>/dev/null | head -1)
|
||||
echo "Invariant Report: $LATEST_REPORT"
|
||||
echo ""
|
||||
|
||||
# Extract summary
|
||||
if [[ -n "$LATEST_REPORT" ]]; then
|
||||
PASSED=$(python3 -c "import json; print(json.load(open('$LATEST_REPORT'))['summary']['passed'])")
|
||||
FAILED=$(python3 -c "import json; print(json.load(open('$LATEST_REPORT'))['summary']['failed'])")
|
||||
echo "Passed: $PASSED"
|
||||
echo "Failed: $FAILED"
|
||||
fi
|
||||
|
||||
# Step 3: Create ProofChain Anchor
|
||||
echo ""
|
||||
echo ">>> Step 3: Creating ProofChain anchor..."
|
||||
|
||||
# Compute combined hash
|
||||
COMBINED_HASH=$(cat "$LATEST_SNAPSHOT" "$LATEST_REPORT" 2>/dev/null | sha256sum | cut -d' ' -f1)
|
||||
|
||||
# Create anchor JSON
|
||||
ANCHOR_JSON=$(cat <<EOF
|
||||
{
|
||||
"anchor_type": "cf_state_anchor",
|
||||
"schema_version": "vm_anchor_v1",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"zone_id": "$ZONE_ID",
|
||||
"account_id": "$ACCOUNT_ID",
|
||||
"snapshot_path": "$LATEST_SNAPSHOT",
|
||||
"report_path": "$LATEST_REPORT",
|
||||
"merkle_root": "$MERKLE_ROOT",
|
||||
"combined_hash": "$COMBINED_HASH",
|
||||
"invariants_passed": $PASSED,
|
||||
"invariants_failed": $FAILED,
|
||||
"status": "$([ $INVARIANT_EXIT -eq 0 ] && echo 'clean' || echo 'anomalies_detected')"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Append to anchors file
|
||||
echo "$ANCHOR_JSON" >> "$ANCHORS_PATH"
|
||||
echo "Anchor appended to: $ANCHORS_PATH"
|
||||
|
||||
# Step 4: Create combined receipt
|
||||
echo ""
|
||||
echo ">>> Step 4: Creating combined receipt..."
|
||||
|
||||
RECEIPT_PATH="${RECEIPTS_DIR}/cf-anchor-${TIMESTAMP}.json"
|
||||
cat > "$RECEIPT_PATH" <<EOF
|
||||
{
|
||||
"receipt_type": "cf_state_anchor_complete",
|
||||
"schema_version": "vm_cf_anchor_v1",
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
||||
"zone_id": "$ZONE_ID",
|
||||
"account_id": "$ACCOUNT_ID",
|
||||
"artifacts": {
|
||||
"snapshot": "$LATEST_SNAPSHOT",
|
||||
"invariant_report": "$LATEST_REPORT",
|
||||
"anchors_file": "$ANCHORS_PATH"
|
||||
},
|
||||
"integrity": {
|
||||
"merkle_root": "$MERKLE_ROOT",
|
||||
"combined_hash": "$COMBINED_HASH",
|
||||
"hash_algorithm": "sha256"
|
||||
},
|
||||
"invariants": {
|
||||
"passed": $PASSED,
|
||||
"failed": $FAILED,
|
||||
"status": "$([ $INVARIANT_EXIT -eq 0 ] && echo 'all_passed' || echo 'failures_detected')"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo "Receipt: $RECEIPT_PATH"
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "======================================"
|
||||
echo "Anchor Complete"
|
||||
echo "======================================"
|
||||
echo "Snapshot: $LATEST_SNAPSHOT"
|
||||
echo "Report: $LATEST_REPORT"
|
||||
echo "Receipt: $RECEIPT_PATH"
|
||||
echo "Merkle Root: $MERKLE_ROOT"
|
||||
echo "Status: $([ $INVARIANT_EXIT -eq 0 ] && echo 'CLEAN' || echo 'ANOMALIES DETECTED')"
|
||||
echo "======================================"
|
||||
|
||||
# Output for CI pipelines
|
||||
echo ""
|
||||
echo "CI_MERKLE_ROOT=$MERKLE_ROOT"
|
||||
echo "CI_SNAPSHOT_PATH=$LATEST_SNAPSHOT"
|
||||
echo "CI_REPORT_PATH=$LATEST_REPORT"
|
||||
echo "CI_RECEIPT_PATH=$RECEIPT_PATH"
|
||||
echo "CI_INVARIANTS_STATUS=$([ $INVARIANT_EXIT -eq 0 ] && echo 'passed' || echo 'failed')"
|
||||
|
||||
# Exit with invariant check result
|
||||
exit $INVARIANT_EXIT
|
||||
Reference in New Issue
Block a user