mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-10 21:24:56 +03:00
392 lines
14 KiB
Python
392 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
BeyondCorp Zero Trust Access Model - Assessment and Audit Tool
|
|
|
|
Audits GCP IAP configuration, Access Context Manager access levels,
|
|
and Endpoint Verification device compliance to validate BeyondCorp
|
|
deployment readiness and ongoing compliance.
|
|
|
|
Requirements:
|
|
pip install google-cloud-iap google-cloud-access-context-manager
|
|
pip install google-cloud-logging google-auth pandas
|
|
"""
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Any
|
|
|
|
|
|
def run_gcloud(args: list[str]) -> dict | list | str:
|
|
"""Execute a gcloud command and return parsed JSON output."""
|
|
cmd = ["gcloud"] + args + ["--format=json"]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
|
if result.returncode != 0:
|
|
print(f"[ERROR] gcloud {' '.join(args[:3])}...: {result.stderr.strip()}")
|
|
return {}
|
|
try:
|
|
return json.loads(result.stdout) if result.stdout.strip() else {}
|
|
except json.JSONDecodeError:
|
|
return result.stdout.strip()
|
|
|
|
|
|
def audit_iap_enabled_services(project_id: str) -> list[dict[str, Any]]:
|
|
"""List all backend services with IAP enabled and their policy bindings."""
|
|
print("\n[1/6] Auditing IAP-enabled backend services...")
|
|
|
|
backends = run_gcloud([
|
|
"compute", "backend-services", "list",
|
|
"--project", project_id
|
|
])
|
|
if not isinstance(backends, list):
|
|
print(" No backend services found or unable to list.")
|
|
return []
|
|
|
|
iap_services = []
|
|
for backend in backends:
|
|
name = backend.get("name", "unknown")
|
|
iap_config = backend.get("iap", {})
|
|
iap_enabled = iap_config.get("enabled", False)
|
|
|
|
if iap_enabled:
|
|
# Get IAM policy for this backend service
|
|
policy = run_gcloud([
|
|
"iap", "web", "get-iam-policy",
|
|
"--resource-type=backend-services",
|
|
"--service", name,
|
|
"--project", project_id
|
|
])
|
|
bindings = policy.get("bindings", []) if isinstance(policy, dict) else []
|
|
|
|
iap_services.append({
|
|
"service_name": name,
|
|
"iap_enabled": True,
|
|
"oauth2_client_id": iap_config.get("oauth2ClientId", "N/A"),
|
|
"bindings_count": len(bindings),
|
|
"bindings": bindings,
|
|
"has_access_level_conditions": any(
|
|
b.get("condition") for b in bindings
|
|
)
|
|
})
|
|
status = "WITH" if iap_services[-1]["has_access_level_conditions"] else "WITHOUT"
|
|
print(f" [IAP ON] {name} - {len(bindings)} bindings {status} access level conditions")
|
|
else:
|
|
print(f" [IAP OFF] {name}")
|
|
|
|
return iap_services
|
|
|
|
|
|
def audit_access_levels(policy_id: str) -> list[dict[str, Any]]:
|
|
"""Enumerate and validate Access Context Manager access levels."""
|
|
print("\n[2/6] Auditing Access Context Manager access levels...")
|
|
|
|
levels = run_gcloud([
|
|
"access-context-manager", "levels", "list",
|
|
"--policy", policy_id
|
|
])
|
|
if not isinstance(levels, list):
|
|
print(" No access levels found or unable to list.")
|
|
return []
|
|
|
|
access_levels = []
|
|
for level in levels:
|
|
name = level.get("name", "").split("/")[-1]
|
|
title = level.get("title", "Untitled")
|
|
basic = level.get("basic", {})
|
|
custom = level.get("custom", {})
|
|
|
|
level_info = {
|
|
"name": name,
|
|
"title": title,
|
|
"type": "basic" if basic else "custom",
|
|
"combining_function": basic.get("combiningFunction", "AND"),
|
|
"conditions_count": len(basic.get("conditions", [])),
|
|
"has_device_policy": False,
|
|
"has_ip_restriction": False,
|
|
"has_region_restriction": False,
|
|
"requires_encryption": False,
|
|
"requires_screenlock": False,
|
|
}
|
|
|
|
for condition in basic.get("conditions", []):
|
|
device_policy = condition.get("devicePolicy", {})
|
|
if device_policy:
|
|
level_info["has_device_policy"] = True
|
|
enc_statuses = device_policy.get("allowedEncryptionStatuses", [])
|
|
if "ENCRYPTED" in enc_statuses:
|
|
level_info["requires_encryption"] = True
|
|
if device_policy.get("requireScreenlock"):
|
|
level_info["requires_screenlock"] = True
|
|
if condition.get("ipSubnetworks"):
|
|
level_info["has_ip_restriction"] = True
|
|
if condition.get("regions"):
|
|
level_info["has_region_restriction"] = True
|
|
level_info["allowed_regions"] = condition["regions"]
|
|
|
|
access_levels.append(level_info)
|
|
print(f" [{level_info['type'].upper()}] {title} ({name})")
|
|
print(f" Device policy: {level_info['has_device_policy']}, "
|
|
f"Encryption: {level_info['requires_encryption']}, "
|
|
f"Screen lock: {level_info['requires_screenlock']}")
|
|
|
|
return access_levels
|
|
|
|
|
|
def audit_endpoint_verification(project_id: str) -> dict[str, Any]:
|
|
"""Check Endpoint Verification device enrollment and compliance."""
|
|
print("\n[3/6] Auditing Endpoint Verification device compliance...")
|
|
|
|
devices = run_gcloud([
|
|
"alpha", "devices", "list",
|
|
"--format=json"
|
|
])
|
|
if not isinstance(devices, list):
|
|
print(" Unable to retrieve device inventory. Ensure Endpoint Verification is deployed.")
|
|
return {"total": 0, "compliant": 0, "non_compliant": 0}
|
|
|
|
stats = {
|
|
"total": len(devices),
|
|
"compliant": 0,
|
|
"non_compliant": 0,
|
|
"os_distribution": {},
|
|
"encryption_status": {"encrypted": 0, "unencrypted": 0, "unknown": 0},
|
|
"non_compliant_devices": []
|
|
}
|
|
|
|
for device in devices:
|
|
os_type = device.get("osType", "UNKNOWN")
|
|
stats["os_distribution"][os_type] = stats["os_distribution"].get(os_type, 0) + 1
|
|
|
|
compliance = device.get("complianceState", "UNKNOWN")
|
|
if compliance == "COMPLIANT":
|
|
stats["compliant"] += 1
|
|
else:
|
|
stats["non_compliant"] += 1
|
|
stats["non_compliant_devices"].append({
|
|
"device_id": device.get("name", "unknown"),
|
|
"os": os_type,
|
|
"compliance_state": compliance
|
|
})
|
|
|
|
compliance_rate = (stats["compliant"] / stats["total"] * 100) if stats["total"] > 0 else 0
|
|
print(f" Total devices: {stats['total']}")
|
|
print(f" Compliant: {stats['compliant']} ({compliance_rate:.1f}%)")
|
|
print(f" Non-compliant: {stats['non_compliant']}")
|
|
print(f" OS distribution: {stats['os_distribution']}")
|
|
|
|
return stats
|
|
|
|
|
|
def audit_iap_access_logs(project_id: str, hours: int = 24) -> dict[str, Any]:
|
|
"""Analyze IAP access logs for denials and anomalies."""
|
|
print(f"\n[4/6] Analyzing IAP access logs (last {hours} hours)...")
|
|
|
|
start_time = (datetime.now(timezone.utc) - timedelta(hours=hours)).isoformat()
|
|
|
|
log_filter = (
|
|
f'resource.type="iap_tunnel" OR resource.type="gce_backend_service" '
|
|
f'AND timestamp >= "{start_time}"'
|
|
)
|
|
|
|
logs = run_gcloud([
|
|
"logging", "read", log_filter,
|
|
"--project", project_id,
|
|
"--limit=1000"
|
|
])
|
|
if not isinstance(logs, list):
|
|
print(" No IAP access logs found or unable to query.")
|
|
return {"total": 0, "allowed": 0, "denied": 0}
|
|
|
|
stats = {
|
|
"total": len(logs),
|
|
"allowed": 0,
|
|
"denied": 0,
|
|
"denied_users": {},
|
|
"denied_applications": {},
|
|
"top_accessed_apps": {}
|
|
}
|
|
|
|
for entry in logs:
|
|
payload = entry.get("jsonPayload", {})
|
|
decision = payload.get("decision", "ALLOW")
|
|
user = payload.get("authenticationInfo", {}).get("principalEmail", "unknown")
|
|
resource = entry.get("resource", {}).get("labels", {}).get("backend_service_name", "unknown")
|
|
|
|
stats["top_accessed_apps"][resource] = stats["top_accessed_apps"].get(resource, 0) + 1
|
|
|
|
if decision == "DENY":
|
|
stats["denied"] += 1
|
|
stats["denied_users"][user] = stats["denied_users"].get(user, 0) + 1
|
|
stats["denied_applications"][resource] = stats["denied_applications"].get(resource, 0) + 1
|
|
else:
|
|
stats["allowed"] += 1
|
|
|
|
denial_rate = (stats["denied"] / stats["total"] * 100) if stats["total"] > 0 else 0
|
|
print(f" Total requests: {stats['total']}")
|
|
print(f" Allowed: {stats['allowed']}")
|
|
print(f" Denied: {stats['denied']} ({denial_rate:.1f}%)")
|
|
if stats["denied_users"]:
|
|
top_denied = sorted(stats["denied_users"].items(), key=lambda x: x[1], reverse=True)[:5]
|
|
print(f" Top denied users: {top_denied}")
|
|
|
|
return stats
|
|
|
|
|
|
def audit_session_policies(project_id: str) -> list[dict[str, Any]]:
|
|
"""Check IAP session duration and re-authentication settings."""
|
|
print("\n[5/6] Auditing IAP session and re-authentication policies...")
|
|
|
|
backends = run_gcloud([
|
|
"compute", "backend-services", "list",
|
|
"--project", project_id
|
|
])
|
|
if not isinstance(backends, list):
|
|
return []
|
|
|
|
session_policies = []
|
|
for backend in backends:
|
|
iap = backend.get("iap", {})
|
|
if not iap.get("enabled"):
|
|
continue
|
|
|
|
name = backend.get("name", "unknown")
|
|
settings = run_gcloud([
|
|
"iap", "settings", "get",
|
|
"--project", project_id,
|
|
"--resource-type=compute",
|
|
"--service", name
|
|
])
|
|
|
|
if isinstance(settings, dict):
|
|
access_settings = settings.get("accessSettings", {})
|
|
reauth = access_settings.get("reauthSettings", {})
|
|
session_policies.append({
|
|
"service": name,
|
|
"max_session_duration": reauth.get("maxAge", "Not configured"),
|
|
"reauth_method": reauth.get("method", "Not configured"),
|
|
"policy_type": reauth.get("policyType", "DEFAULT")
|
|
})
|
|
print(f" {name}: session={reauth.get('maxAge', 'default')}, "
|
|
f"method={reauth.get('method', 'default')}")
|
|
|
|
return session_policies
|
|
|
|
|
|
def generate_compliance_report(
|
|
project_id: str,
|
|
iap_services: list,
|
|
access_levels: list,
|
|
device_stats: dict,
|
|
log_stats: dict,
|
|
session_policies: list
|
|
) -> str:
|
|
"""Generate a comprehensive BeyondCorp compliance report."""
|
|
print("\n[6/6] Generating BeyondCorp compliance report...")
|
|
|
|
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
|
|
total_services = len(iap_services)
|
|
with_conditions = sum(1 for s in iap_services if s["has_access_level_conditions"])
|
|
device_compliance = (
|
|
(device_stats["compliant"] / device_stats["total"] * 100)
|
|
if device_stats["total"] > 0 else 0
|
|
)
|
|
|
|
report = f"""
|
|
BeyondCorp Zero Trust Compliance Audit Report
|
|
{'=' * 55}
|
|
Project: {project_id}
|
|
Generated: {now}
|
|
Audit Period: Last 24 hours
|
|
|
|
1. IAP COVERAGE
|
|
IAP-enabled services: {total_services}
|
|
Services with access levels: {with_conditions} / {total_services}
|
|
Coverage rate: {(with_conditions / total_services * 100) if total_services else 0:.1f}%
|
|
|
|
2. ACCESS LEVELS
|
|
Total access levels defined: {len(access_levels)}
|
|
With device policy: {sum(1 for a in access_levels if a['has_device_policy'])}
|
|
Requiring encryption: {sum(1 for a in access_levels if a['requires_encryption'])}
|
|
Requiring screen lock: {sum(1 for a in access_levels if a['requires_screenlock'])}
|
|
With IP restrictions: {sum(1 for a in access_levels if a['has_ip_restriction'])}
|
|
With region restrictions: {sum(1 for a in access_levels if a['has_region_restriction'])}
|
|
|
|
3. DEVICE COMPLIANCE
|
|
Total enrolled devices: {device_stats['total']}
|
|
Compliant devices: {device_stats['compliant']} ({device_compliance:.1f}%)
|
|
Non-compliant devices: {device_stats['non_compliant']}
|
|
|
|
4. ACCESS LOG ANALYSIS (24h)
|
|
Total access requests: {log_stats['total']}
|
|
Allowed: {log_stats['allowed']}
|
|
Denied: {log_stats['denied']}
|
|
Denial rate: {(log_stats['denied'] / log_stats['total'] * 100) if log_stats['total'] else 0:.1f}%
|
|
|
|
5. SESSION POLICIES
|
|
Services with re-auth policy: {len(session_policies)}
|
|
|
|
6. RECOMMENDATIONS
|
|
"""
|
|
recommendations = []
|
|
if with_conditions < total_services:
|
|
recommendations.append(
|
|
f" - {total_services - with_conditions} IAP services lack access level conditions. "
|
|
"Add device posture requirements."
|
|
)
|
|
if device_compliance < 95:
|
|
recommendations.append(
|
|
f" - Device compliance is {device_compliance:.1f}% (target: 95%). "
|
|
"Remediate non-compliant devices."
|
|
)
|
|
if not any(a["requires_encryption"] for a in access_levels):
|
|
recommendations.append(
|
|
" - No access levels require disk encryption. Add encryption requirement to sensitive app tiers."
|
|
)
|
|
if len(session_policies) < total_services:
|
|
recommendations.append(
|
|
f" - {total_services - len(session_policies)} services lack explicit session policies. "
|
|
"Configure re-authentication."
|
|
)
|
|
if not recommendations:
|
|
recommendations.append(" - No critical issues found. Continue monitoring.")
|
|
|
|
report += "\n".join(recommendations)
|
|
|
|
return report
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python process.py <project-id> [access-policy-id]")
|
|
print("\nExample:")
|
|
print(" python process.py my-gcp-project 123456789")
|
|
sys.exit(1)
|
|
|
|
project_id = sys.argv[1]
|
|
policy_id = sys.argv[2] if len(sys.argv) > 2 else None
|
|
|
|
print(f"BeyondCorp Zero Trust Audit - Project: {project_id}")
|
|
print("=" * 55)
|
|
|
|
iap_services = audit_iap_enabled_services(project_id)
|
|
access_levels = audit_access_levels(policy_id) if policy_id else []
|
|
device_stats = audit_endpoint_verification(project_id)
|
|
log_stats = audit_iap_access_logs(project_id)
|
|
session_policies = audit_session_policies(project_id)
|
|
|
|
report = generate_compliance_report(
|
|
project_id, iap_services, access_levels,
|
|
device_stats, log_stats, session_policies
|
|
)
|
|
print(report)
|
|
|
|
report_path = f"beyondcorp_audit_{project_id}_{datetime.now().strftime('%Y%m%d')}.txt"
|
|
with open(report_path, "w") as f:
|
|
f.write(report)
|
|
print(f"\nReport saved to: {report_path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|