#!/usr/bin/env python3 """ Cloudflare Infrastructure Monitoring Dashboard Provides real-time monitoring of Cloudflare resources and services """ import os import json import time import requests from datetime import datetime, timedelta from typing import Dict, List, Any class CloudflareMonitor: def __init__(self): self.base_url = "https://api.cloudflare.com/client/v4" self.headers = { "Authorization": f"Bearer {os.getenv('CLOUDFLARE_API_TOKEN')}", "Content-Type": "application/json", } self.account_id = os.getenv("CLOUDFLARE_ACCOUNT_ID") if not self.account_id or not os.getenv("CLOUDFLARE_API_TOKEN"): raise ValueError("Missing Cloudflare credentials in environment") def make_request(self, endpoint: str) -> Dict[str, Any]: """Make API request with error handling""" url = f"{self.base_url}{endpoint}" try: response = requests.get(url, headers=self.headers, timeout=10) response.raise_for_status() return response.json() except requests.RequestException as e: return {"success": False, "errors": [str(e)]} def get_account_info(self) -> Dict[str, Any]: """Get account information""" return self.make_request(f"/accounts/{self.account_id}") def get_zones(self) -> List[Dict[str, Any]]: """Get all zones""" result = self.make_request(f"/zones?account.id={self.account_id}&per_page=50") return result.get("result", []) if result.get("success") else [] def get_zone_analytics(self, zone_id: str) -> Dict[str, Any]: """Get zone analytics for the last hour""" since = (datetime.now() - timedelta(hours=1)).isoformat() return self.make_request(f"/zones/{zone_id}/analytics/dashboard?since={since}") def get_waf_rules(self, zone_id: str) -> List[Dict[str, Any]]: """Get WAF rules for a zone""" result = self.make_request(f"/zones/{zone_id}/firewall/waf/packages") if result.get("success"): packages = result.get("result", []) rules = [] for package in packages: rules_result = self.make_request( f"/zones/{zone_id}/firewall/waf/packages/{package['id']}/rules" ) if rules_result.get("success"): rules.extend(rules_result.get("result", [])) return rules return [] def get_tunnels(self) -> List[Dict[str, Any]]: """Get Cloudflare Tunnels""" result = self.make_request(f"/accounts/{self.account_id}/cfd_tunnel") return result.get("result", []) if result.get("success") else [] def get_dns_records(self, zone_id: str) -> List[Dict[str, Any]]: """Get DNS records for a zone""" result = self.make_request(f"/zones/{zone_id}/dns_records?per_page=100") return result.get("result", []) if result.get("success") else [] def get_health_status(self) -> Dict[str, Any]: """Get overall health status""" status = "healthy" issues = [] # Check zones zones = self.get_zones() if not zones: issues.append("No zones found") status = "warning" # Check account access account_info = self.get_account_info() if not account_info.get("success"): issues.append("Account access failed") status = "critical" return {"status": status, "issues": issues} def format_table(data: List[Dict[str, Any]], headers: List[str]) -> str: """Format data as a table""" if not data: return "No data available" # Calculate column widths col_widths = [len(header) for header in headers] for row in data: for i, header in enumerate(headers): value = str(row.get(header, "")) col_widths[i] = max(col_widths[i], len(value)) # Create header row header_row = " | ".join( header.ljust(col_widths[i]) for i, header in enumerate(headers) ) separator = "-" * len(header_row) # Create data rows rows = [header_row, separator] for row in data: row_data = [ str(row.get(header, "")).ljust(col_widths[i]) for i, header in enumerate(headers) ] rows.append(" | ".join(row_data)) return "\n".join(rows) def main(): print("🌐 Cloudflare Infrastructure Monitoring Dashboard") print("=" * 60) print(f"Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print() try: monitor = CloudflareMonitor() # Health check print("🔍 Health Status") print("-" * 30) health = monitor.get_health_status() status_emoji = {"healthy": "✅", "warning": "⚠️", "critical": "❌"} print( f"Status: {status_emoji.get(health['status'], '❓')} {health['status'].upper()}" ) if health["issues"]: for issue in health["issues"]: print(f" - {issue}") print() # Account information print("🏢 Account Information") print("-" * 30) account_info = monitor.get_account_info() if account_info.get("success"): account = account_info["result"] print(f"Name: {account.get('name', 'N/A')}") print(f"Type: {account.get('type', 'N/A')}") print(f"Created: {account.get('created_on', 'N/A')}") else: print("Failed to retrieve account information") print() # Zones overview print("🌐 Zones Overview") print("-" * 30) zones = monitor.get_zones() zone_data = [] for zone in zones[:10]: # Limit to first 10 zones zone_data.append( { "Name": zone.get("name", "N/A"), "Status": zone.get("status", "N/A"), "Plan": zone.get("plan", {}).get("name", "N/A"), "Development": zone.get("development_mode", "N/A"), } ) print(format_table(zone_data, ["Name", "Status", "Plan", "Development"])) print(f"Total zones: {len(zones)}") print() # DNS Records (for first zone) dns_records = [] waf_rules = [] if zones: first_zone = zones[0] print("📋 DNS Records (First Zone)") print("-" * 30) dns_records = monitor.get_dns_records(first_zone["id"]) dns_data = [] for record in dns_records[:15]: # Limit to first 15 records dns_data.append( { "Type": record.get("type", "N/A"), "Name": record.get("name", "N/A"), "Content": record.get("content", "N/A")[:40] + "..." if len(record.get("content", "")) > 40 else record.get("content", "N/A"), } ) print(format_table(dns_data, ["Type", "Name", "Content"])) print(f"Total DNS records: {len(dns_records)}") print() # Tunnels print("🔗 Cloudflare Tunnels") print("-" * 30) tunnels = monitor.get_tunnels() tunnel_data = [] for tunnel in tunnels: tunnel_data.append( { "Name": tunnel.get("name", "N/A"), "Status": tunnel.get("status", "N/A"), "Connections": len(tunnel.get("connections", [])), } ) print(format_table(tunnel_data, ["Name", "Status", "Connections"])) print(f"Total tunnels: {len(tunnels)}") print() # WAF Rules (for first zone) if zones: first_zone = zones[0] print("🛡️ WAF Rules (First Zone)") print("-" * 30) waf_rules = monitor.get_waf_rules(first_zone["id"]) waf_data = [] for rule in waf_rules[:10]: # Limit to first 10 rules waf_data.append( { "ID": rule.get("id", "N/A"), "Description": rule.get("description", "N/A")[:50] + "..." if len(rule.get("description", "")) > 50 else rule.get("description", "N/A"), "Mode": rule.get("mode", "N/A"), } ) print(format_table(waf_data, ["ID", "Description", "Mode"])) print(f"Total WAF rules: {len(waf_rules)}") print() # Summary print("📊 Summary") print("-" * 30) print(f"Zones: {len(zones)}") print(f"Tunnels: {len(tunnels)}") if zones: print(f"DNS Records (first zone): {len(dns_records)}") print(f"WAF Rules (first zone): {len(waf_rules)}") except Exception as e: print(f"❌ Error: {e}") print("Please ensure your Cloudflare credentials are properly configured.") if __name__ == "__main__": main()