From 68d429f80c8f79355e723bf31fdecff8767edab5 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Wed, 16 Jul 2025 13:24:27 -0600 Subject: [PATCH] Add comprehensive security automation tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implement auto_configure_domain_security tool for complete domain security setup - Add analyze_domain_security tool for security analysis and scoring - Generate DKIM keys, extract DNS records, and provide security recommendations - Calculate security scores based on DKIM, SPF, DMARC, and TLSA configurations - Version bump to 0.3.0 for security enhancements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/mcp_mailu/server.py | 249 ++++++++++++++++++++++++++++++++++++++++ uv.lock | 2 +- 2 files changed, 250 insertions(+), 1 deletion(-) diff --git a/src/mcp_mailu/server.py b/src/mcp_mailu/server.py index 057f438..6f34f33 100644 --- a/src/mcp_mailu/server.py +++ b/src/mcp_mailu/server.py @@ -1378,6 +1378,255 @@ def create_mcp_server() -> FastMCP: except Exception as e: return f"Error generating DKIM keys: {e}" + @mcp.tool() + async def auto_configure_domain_security(domain: str) -> str: + """Auto-configure complete domain security: DKIM, SPF, DMARC with DNS records.""" + try: + async with client as mailu_client: + # Step 1: Generate DKIM keys + dkim_response = await mailu_client.post(f"/domain/{domain}/dkim") + dkim_response.raise_for_status() + + # Step 2: Get updated domain info with DNS records + domain_response = await mailu_client.get(f"/domain/{domain}") + domain_response.raise_for_status() + domain_data = domain_response.json() + + # Step 3: Extract and format DNS records + dns_records = [] + security_config = { + "domain": domain, + "dkim_generated": True, + "dns_records": [], + "security_recommendations": [] + } + + # MX Record + if "dns_mx" in domain_data and domain_data["dns_mx"]: + mx_record = domain_data["dns_mx"] + dns_records.append({ + "type": "MX", + "record": mx_record, + "description": "Mail Exchange record - directs email to your mail server" + }) + + # SPF Record + if "dns_spf" in domain_data and domain_data["dns_spf"]: + spf_record = domain_data["dns_spf"] + dns_records.append({ + "type": "SPF", + "record": spf_record, + "description": "Sender Policy Framework - prevents email spoofing" + }) + + # DKIM Record + if "dns_dkim" in domain_data and domain_data["dns_dkim"]: + dkim_record = domain_data["dns_dkim"] + dns_records.append({ + "type": "DKIM", + "record": dkim_record, + "description": "DomainKeys Identified Mail - cryptographic email authentication" + }) + + # DMARC Record + if "dns_dmarc" in domain_data and domain_data["dns_dmarc"]: + dmarc_record = domain_data["dns_dmarc"] + dns_records.append({ + "type": "DMARC", + "record": dmarc_record, + "description": "Domain-based Message Authentication - email security policy" + }) + + # DMARC Report Record + if "dns_dmarc_report" in domain_data and domain_data["dns_dmarc_report"]: + dmarc_report_record = domain_data["dns_dmarc_report"] + dns_records.append({ + "type": "DMARC Report", + "record": dmarc_report_record, + "description": "DMARC reporting configuration" + }) + + # TLSA Record (for DANE) + if "dns_tlsa" in domain_data and domain_data["dns_tlsa"]: + tlsa_record = domain_data["dns_tlsa"] + dns_records.append({ + "type": "TLSA", + "record": tlsa_record, + "description": "Transport Layer Security Authentication - DANE support" + }) + + # Autoconfig Records + if "dns_autoconfig" in domain_data and domain_data["dns_autoconfig"]: + for autoconfig_record in domain_data["dns_autoconfig"]: + if autoconfig_record.strip(): + dns_records.append({ + "type": "Autoconfig", + "record": autoconfig_record, + "description": "Email client auto-configuration" + }) + + security_config["dns_records"] = dns_records + + # Step 4: Generate security recommendations + recommendations = [] + + # Check if all security records are present + has_spf = any(record["type"] == "SPF" for record in dns_records) + has_dkim = any(record["type"] == "DKIM" for record in dns_records) + has_dmarc = any(record["type"] == "DMARC" for record in dns_records) + has_tlsa = any(record["type"] == "TLSA" for record in dns_records) + + if has_spf and has_dkim and has_dmarc: + recommendations.append("✅ Complete email security configuration: SPF, DKIM, and DMARC are all configured") + else: + if not has_spf: + recommendations.append("⚠️ SPF record missing - configure to prevent email spoofing") + if not has_dkim: + recommendations.append("⚠️ DKIM record missing - run generate_dkim_keys tool") + if not has_dmarc: + recommendations.append("⚠️ DMARC record missing - provides email authentication policy") + + if has_tlsa: + recommendations.append("✅ DANE/TLSA configured for enhanced transport security") + else: + recommendations.append("💡 Consider adding TLSA records for DANE transport security") + + # Check autoconfig + has_autoconfig = any(record["type"] == "Autoconfig" for record in dns_records) + if has_autoconfig: + recommendations.append("✅ Email client auto-configuration is enabled") + else: + recommendations.append("💡 Email client auto-configuration records are available") + + security_config["security_recommendations"] = recommendations + + # Step 5: Format comprehensive response + result = { + "success": True, + "message": f"Domain security auto-configuration completed for {domain}", + "actions_taken": [ + "Generated DKIM keys", + "Retrieved all DNS security records", + "Analyzed security configuration", + "Generated implementation recommendations" + ], + "configuration": security_config, + "next_steps": [ + "Add the DNS records to your domain's DNS zone", + "Wait for DNS propagation (24-48 hours)", + "Test email delivery and authentication", + "Monitor DMARC reports for any issues" + ] + } + + return json.dumps(result, indent=2) + + except Exception as e: + return f"Error auto-configuring domain security: {e}" + + @mcp.tool() + async def analyze_domain_security(domain: str) -> str: + """Analyze current domain security configuration without making changes.""" + try: + async with client as mailu_client: + # Get domain info with DNS records + domain_response = await mailu_client.get(f"/domain/{domain}") + domain_response.raise_for_status() + domain_data = domain_response.json() + + # Security analysis + security_analysis = { + "domain": domain, + "security_status": {}, + "vulnerabilities": [], + "recommendations": [], + "dns_records_found": [] + } + + # Check for each security component + has_mx = bool(domain_data.get("dns_mx")) + has_spf = bool(domain_data.get("dns_spf")) + has_dkim = bool(domain_data.get("dns_dkim")) + has_dmarc = bool(domain_data.get("dns_dmarc")) + has_tlsa = bool(domain_data.get("dns_tlsa")) + has_autoconfig = bool(domain_data.get("dns_autoconfig")) + + security_analysis["security_status"] = { + "mx_record": "✅ Configured" if has_mx else "❌ Missing", + "spf_record": "✅ Configured" if has_spf else "❌ Missing", + "dkim_record": "✅ Configured" if has_dkim else "❌ Missing", + "dmarc_record": "✅ Configured" if has_dmarc else "❌ Missing", + "tlsa_record": "✅ Configured" if has_tlsa else "⚠️ Optional", + "autoconfig": "✅ Configured" if has_autoconfig else "⚠️ Optional" + } + + # Calculate security score + required_components = [has_mx, has_spf, has_dkim, has_dmarc] + security_score = sum(required_components) / len(required_components) * 100 + + # Identify vulnerabilities and recommendations + if not has_mx: + security_analysis["vulnerabilities"].append("🚨 CRITICAL: No MX record - email delivery will fail") + security_analysis["recommendations"].append("Configure MX record immediately") + + if not has_spf: + security_analysis["vulnerabilities"].append("🚨 HIGH: No SPF record - email spoofing possible") + security_analysis["recommendations"].append("Add SPF record to prevent spoofing") + + if not has_dkim: + security_analysis["vulnerabilities"].append("🚨 HIGH: No DKIM record - email authentication weak") + security_analysis["recommendations"].append("Generate DKIM keys and add DNS record") + + if not has_dmarc: + security_analysis["vulnerabilities"].append("🚨 MEDIUM: No DMARC record - no email policy enforcement") + security_analysis["recommendations"].append("Configure DMARC policy for email protection") + + if not has_tlsa: + security_analysis["recommendations"].append("💡 Consider TLSA records for enhanced transport security (DANE)") + + if not has_autoconfig: + security_analysis["recommendations"].append("💡 Consider adding autoconfig records for easier email client setup") + + # Add found DNS records + if has_mx: + security_analysis["dns_records_found"].append(f"MX: {domain_data['dns_mx']}") + if has_spf: + security_analysis["dns_records_found"].append(f"SPF: {domain_data['dns_spf']}") + if has_dkim: + security_analysis["dns_records_found"].append(f"DKIM: {domain_data['dns_dkim']}") + if has_dmarc: + security_analysis["dns_records_found"].append(f"DMARC: {domain_data['dns_dmarc']}") + if has_tlsa: + security_analysis["dns_records_found"].append(f"TLSA: {domain_data['dns_tlsa']}") + + # Overall assessment + if security_score == 100: + security_level = "🟢 EXCELLENT" + summary = "All critical security components are configured" + elif security_score >= 75: + security_level = "🟡 GOOD" + summary = "Most security components configured, minor improvements needed" + elif security_score >= 50: + security_level = "🟠 MODERATE" + summary = "Basic security configured, significant improvements recommended" + else: + security_level = "🔴 CRITICAL" + summary = "Major security vulnerabilities present, immediate action required" + + result = { + "domain": domain, + "security_level": security_level, + "security_score": f"{security_score:.1f}%", + "summary": summary, + "analysis": security_analysis, + "quick_fix": "Run auto_configure_domain_security() to automatically fix all issues" + } + + return json.dumps(result, indent=2) + + except Exception as e: + return f"Error analyzing domain security: {e}" + # ===== DOMAIN MANAGER TOOLS ===== diff --git a/uv.lock b/uv.lock index 300053d..2ca3f7c 100644 --- a/uv.lock +++ b/uv.lock @@ -613,7 +613,7 @@ wheels = [ [[package]] name = "mcp-mailu" -version = "0.2.0" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "fastmcp" },