mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-14 06:54:57 +03:00
240 lines
7.7 KiB
Python
240 lines
7.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
GCP Organization Policy Constraints Management Script
|
|
|
|
Automates auditing, deploying, and monitoring organization policies
|
|
across a GCP organization hierarchy.
|
|
"""
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
|
|
SECURITY_CONSTRAINTS = {
|
|
"compute.vmExternalIpAccess": {
|
|
"type": "list",
|
|
"action": "deny_all",
|
|
"description": "Deny external IP addresses on VMs"
|
|
},
|
|
"compute.requireOsLogin": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Require OS Login for SSH access"
|
|
},
|
|
"compute.disableSerialPortAccess": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Disable serial port access on VMs"
|
|
},
|
|
"iam.disableServiceAccountKeyCreation": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Disable service account key creation"
|
|
},
|
|
"storage.uniformBucketLevelAccess": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Enforce uniform bucket-level access"
|
|
},
|
|
"sql.restrictPublicIp": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Restrict public IP on Cloud SQL"
|
|
},
|
|
"gcp.resourceLocations": {
|
|
"type": "list",
|
|
"action": "allow",
|
|
"values": ["in:us-locations", "in:eu-locations"],
|
|
"description": "Restrict resource locations to US and EU"
|
|
},
|
|
"compute.disableNestedVirtualization": {
|
|
"type": "boolean",
|
|
"enforced": True,
|
|
"description": "Disable nested virtualization"
|
|
}
|
|
}
|
|
|
|
|
|
def run_gcloud(args):
|
|
"""Execute a gcloud command and return output."""
|
|
cmd = ["gcloud"] + args + ["--format=json"]
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
if result.returncode != 0:
|
|
return None, result.stderr
|
|
try:
|
|
return json.loads(result.stdout) if result.stdout.strip() else {}, None
|
|
except json.JSONDecodeError:
|
|
return result.stdout, None
|
|
|
|
|
|
def audit_org_policies(org_id):
|
|
"""Audit current organization policies and identify gaps."""
|
|
print(f"[*] Auditing organization policies for org: {org_id}")
|
|
|
|
results, err = run_gcloud([
|
|
"org-policies", "list",
|
|
f"--organization={org_id}"
|
|
])
|
|
|
|
if err:
|
|
print(f"[!] Error listing policies: {err}")
|
|
return None
|
|
|
|
active_constraints = set()
|
|
if isinstance(results, list):
|
|
for policy in results:
|
|
constraint = policy.get("constraint", "")
|
|
active_constraints.add(constraint.replace("constraints/", ""))
|
|
|
|
print(f"\n[+] Active organization policies: {len(active_constraints)}")
|
|
|
|
# Check against recommended baseline
|
|
missing = []
|
|
present = []
|
|
for constraint in SECURITY_CONSTRAINTS:
|
|
if constraint in active_constraints:
|
|
present.append(constraint)
|
|
print(f" [OK] {constraint}: {SECURITY_CONSTRAINTS[constraint]['description']}")
|
|
else:
|
|
missing.append(constraint)
|
|
print(f" [MISSING] {constraint}: {SECURITY_CONSTRAINTS[constraint]['description']}")
|
|
|
|
return {
|
|
"active": list(active_constraints),
|
|
"baseline_present": present,
|
|
"baseline_missing": missing,
|
|
"compliance_score": len(present) / len(SECURITY_CONSTRAINTS) * 100
|
|
}
|
|
|
|
|
|
def generate_policy_yaml(constraint_name, config, dry_run=False):
|
|
"""Generate YAML policy definition for a constraint."""
|
|
import yaml
|
|
|
|
policy = {"constraint": f"constraints/{constraint_name}"}
|
|
|
|
if config["type"] == "boolean":
|
|
policy["booleanPolicy"] = {"enforced": config["enforced"]}
|
|
elif config["type"] == "list":
|
|
if config.get("action") == "deny_all":
|
|
policy["listPolicy"] = {"allValues": "DENY"}
|
|
elif config.get("action") == "allow":
|
|
policy["listPolicy"] = {"allowedValues": config["values"]}
|
|
|
|
if dry_run:
|
|
policy["dryRunSpec"] = True
|
|
|
|
return yaml.dump(policy, default_flow_style=False)
|
|
|
|
|
|
def deploy_baseline_policies(org_id, dry_run=True):
|
|
"""Deploy baseline organization policies."""
|
|
mode = "dry-run" if dry_run else "enforced"
|
|
print(f"\n[*] Deploying baseline policies in {mode} mode for org: {org_id}")
|
|
|
|
for constraint, config in SECURITY_CONSTRAINTS.items():
|
|
print(f"\n Deploying: {constraint}")
|
|
print(f" Description: {config['description']}")
|
|
|
|
# Generate policy file
|
|
import tempfile
|
|
policy_yaml = generate_policy_yaml(constraint, config, dry_run)
|
|
|
|
with tempfile.NamedTemporaryFile(
|
|
mode="w", suffix=".yaml", delete=False, prefix=f"policy_{constraint}_"
|
|
) as f:
|
|
f.write(policy_yaml)
|
|
policy_file = f.name
|
|
|
|
# Apply policy
|
|
_, err = run_gcloud([
|
|
"org-policies", "set-policy",
|
|
f"--organization={org_id}",
|
|
policy_file
|
|
])
|
|
|
|
if err:
|
|
print(f" [FAIL] Error applying {constraint}: {err}")
|
|
else:
|
|
print(f" [OK] Successfully applied {constraint}")
|
|
|
|
|
|
def check_policy_violations(org_id, constraint_name):
|
|
"""Check for resources violating a specific policy."""
|
|
print(f"\n[*] Checking violations for: {constraint_name}")
|
|
|
|
results, err = run_gcloud([
|
|
"asset", "search-all-resources",
|
|
f"--scope=organizations/{org_id}",
|
|
f"--query=policy:constraints/{constraint_name}"
|
|
])
|
|
|
|
if err:
|
|
print(f"[!] Error checking violations: {err}")
|
|
return []
|
|
|
|
if isinstance(results, list):
|
|
print(f"[+] Found {len(results)} potentially affected resources")
|
|
for resource in results[:10]:
|
|
print(f" - {resource.get('name', 'unknown')}")
|
|
return results
|
|
|
|
return []
|
|
|
|
|
|
def generate_compliance_report(audit_results, org_id):
|
|
"""Generate a compliance report for organization policies."""
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
report = f"""
|
|
{'='*60}
|
|
GCP Organization Policy Compliance Report
|
|
Organization: {org_id}
|
|
Generated: {timestamp}
|
|
{'='*60}
|
|
|
|
Compliance Score: {audit_results['compliance_score']:.1f}%
|
|
|
|
Baseline Policies Present ({len(audit_results['baseline_present'])}):
|
|
"""
|
|
for p in audit_results['baseline_present']:
|
|
report += f" [PASS] {p}\n"
|
|
|
|
report += f"\nBaseline Policies Missing ({len(audit_results['baseline_missing'])}):\n"
|
|
for m in audit_results['baseline_missing']:
|
|
report += f" [FAIL] {m} - {SECURITY_CONSTRAINTS[m]['description']}\n"
|
|
|
|
report += f"\nTotal Active Policies: {len(audit_results['active'])}\n"
|
|
report += f"\nRecommendation: {'Compliant' if audit_results['compliance_score'] >= 80 else 'Remediation Required'}\n"
|
|
|
|
return report
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="GCP Organization Policy Management")
|
|
parser.add_argument("--org-id", required=True, help="GCP Organization ID")
|
|
parser.add_argument("--audit", action="store_true", help="Audit existing policies")
|
|
parser.add_argument("--deploy", action="store_true", help="Deploy baseline policies")
|
|
parser.add_argument("--dry-run", action="store_true", default=True, help="Deploy in dry-run mode")
|
|
parser.add_argument("--enforce", action="store_true", help="Deploy in enforced mode")
|
|
parser.add_argument("--check-violations", type=str, help="Check violations for a constraint")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.audit:
|
|
results = audit_org_policies(args.org_id)
|
|
if results:
|
|
report = generate_compliance_report(results, args.org_id)
|
|
print(report)
|
|
|
|
if args.deploy:
|
|
dry_run = not args.enforce
|
|
deploy_baseline_policies(args.org_id, dry_run=dry_run)
|
|
|
|
if args.check_violations:
|
|
check_policy_violations(args.org_id, args.check_violations)
|