npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
Overview
The GCP Organization Policy Service provides centralized and programmatic control over cloud resources. Organization policies configure constraints that restrict one or more Google Cloud services, enforced at organization, folder, or project levels. They improve security by blocking external IPs, requiring encryption, and minimizing unauthorized access. Changes can take up to 15 minutes to propagate.
When to Use
- When deploying or configuring implementing gcp organization policy constraints capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- GCP Organization with Organization Administrator role
gcloudCLI configured and authenticated- Terraform or gcloud for policy management
- Organization Policy Administrator IAM role (
roles/orgpolicy.policyAdmin)
Core Concepts
Constraint Types
- List Constraints: Allow or deny specific values (e.g., allowed regions)
- Boolean Constraints: Enable or disable a capability (e.g., disable serial port access)
- Custom Constraints: User-defined rules targeting specific resource fields (Preview)
Policy Inheritance
Policies inherit from the lowest ancestor with an enforced policy. If no ancestor has a policy, Google's managed default behavior applies.
Essential Security Constraints
Restrict VM External IP Addresses
# Deny external IP addresses on all VMs
gcloud resource-manager org-policies set-policy \
--organization=ORGANIZATION_ID \
policy.yamlpolicy.yaml:
constraint: constraints/compute.vmExternalIpAccess
listPolicy:
allValues: DENYRestrict Resource Locations
gcloud org-policies set-policy \
--organization=ORGANIZATION_ID \
location-policy.yamllocation-policy.yaml:
constraint: constraints/gcp.resourceLocations
listPolicy:
allowedValues:
- "in:us-locations"
- "in:eu-locations"Disable Default Service Account Creation
constraint: constraints/iam.automaticIamGrantsForDefaultServiceAccounts
booleanPolicy:
enforced: trueRequire OS Login for SSH
constraint: constraints/compute.requireOsLogin
booleanPolicy:
enforced: trueDisable Serial Port Access
constraint: constraints/compute.disableSerialPortAccess
booleanPolicy:
enforced: trueEnforce Uniform Bucket-Level Access
constraint: constraints/storage.uniformBucketLevelAccess
booleanPolicy:
enforced: trueRestrict Public IP on Cloud SQL
constraint: constraints/sql.restrictPublicIp
booleanPolicy:
enforced: trueDisable Service Account Key Creation
constraint: constraints/iam.disableServiceAccountKeyCreation
booleanPolicy:
enforced: trueTerraform Implementation
resource "google_organization_policy" "restrict_vm_external_ip" {
org_id = var.org_id
constraint = "constraints/compute.vmExternalIpAccess"
list_policy {
deny {
all = true
}
}
}
resource "google_organization_policy" "restrict_locations" {
org_id = var.org_id
constraint = "constraints/gcp.resourceLocations"
list_policy {
allow {
values = ["in:us-locations", "in:eu-locations"]
}
}
}
resource "google_organization_policy" "require_os_login" {
org_id = var.org_id
constraint = "constraints/compute.requireOsLogin"
boolean_policy {
enforced = true
}
}
resource "google_folder_organization_policy" "dev_folder_external_ip" {
folder = google_folder.dev.name
constraint = "constraints/compute.vmExternalIpAccess"
list_policy {
allow {
values = ["projects/dev-project/zones/us-central1-a/instances/bastion-host"]
}
}
}Dry-Run Testing
Use Policy Intelligence tools to test changes before enforcement:
# Create a dry-run policy to monitor impact
gcloud org-policies set-policy \
--organization=ORGANIZATION_ID \
dry-run-policy.yamldry-run-policy.yaml:
constraint: constraints/compute.vmExternalIpAccess
listPolicy:
allValues: DENY
dryRunSpec: true# Check violations against dry-run policy
gcloud org-policies list-custom-constraints \
--organization=ORGANIZATION_IDCustom Constraints
# custom-constraint.yaml
name: organizations/ORGANIZATION_ID/customConstraints/custom.disableGKEAutoUpgrade
resourceTypes:
- container.googleapis.com/NodePool
methodTypes:
- CREATE
- UPDATE
condition: "resource.management.autoUpgrade == true"
actionType: DENY
displayName: Deny GKE auto-upgrade on node pools
description: Prevents enabling auto-upgrade on GKE node pools for controlled upgradesgcloud org-policies set-custom-constraint custom-constraint.yamlMonitoring and Compliance
List active policies
gcloud org-policies list --organization=ORGANIZATION_IDDescribe a specific policy
gcloud org-policies describe constraints/compute.vmExternalIpAccess \
--organization=ORGANIZATION_IDAudit policy violations with Cloud Asset Inventory
gcloud asset search-all-resources \
--scope=organizations/ORGANIZATION_ID \
--query="policy:constraints/compute.vmExternalIpAccess"Recommended Baseline Policies
| Constraint | Type | Scope | Purpose |
|---|---|---|---|
| compute.vmExternalIpAccess | List/Deny | Org | Prevent public VM IPs |
| gcp.resourceLocations | List/Allow | Org | Restrict to approved regions |
| iam.disableServiceAccountKeyCreation | Boolean | Org | Force Workload Identity |
| compute.requireOsLogin | Boolean | Org | Mandate OS Login for SSH |
| storage.uniformBucketLevelAccess | Boolean | Org | Enforce uniform bucket access |
| sql.restrictPublicIp | Boolean | Org | No public Cloud SQL |
| compute.disableSerialPortAccess | Boolean | Org | Disable serial port |
| compute.disableNestedVirtualization | Boolean | Org | No nested VMs |
References
- GCP Organization Policy Constraints: https://docs.google.com/resource-manager/docs/organization-policy/org-policy-constraints
- GCP Policy Intelligence: https://cloud.google.com/policy-intelligence
- CIS GCP Foundations Benchmark
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md2.0 KB
API Reference: Implementing GCP Organization Policy Constraints
gcloud CLI Commands
# List all org policies
gcloud org-policies list --organization=ORG_ID
# Describe specific constraint
gcloud org-policies describe constraints/compute.vmExternalIpAccess --organization=ORG_ID
# Set policy from YAML
gcloud resource-manager org-policies set-policy policy.yaml --organization=ORG_ID
# Set custom constraint
gcloud org-policies set-custom-constraint custom-constraint.yaml
# Check effective policy on project
gcloud org-policies list --project=PROJECT_IDBaseline Security Constraints
| Constraint | Type | Purpose |
|---|---|---|
compute.vmExternalIpAccess |
List/Deny | Block public VM IPs |
compute.requireOsLogin |
Boolean | Mandate OS Login for SSH |
compute.disableSerialPortAccess |
Boolean | Disable serial port |
storage.uniformBucketLevelAccess |
Boolean | Uniform bucket ACLs |
sql.restrictPublicIp |
Boolean | No public Cloud SQL |
iam.disableServiceAccountKeyCreation |
Boolean | Force Workload Identity |
gcp.resourceLocations |
List/Allow | Restrict to approved regions |
Policy YAML Formats
Boolean Policy
constraint: constraints/compute.requireOsLogin
booleanPolicy:
enforced: trueList Policy (Deny All)
constraint: constraints/compute.vmExternalIpAccess
listPolicy:
allValues: DENYList Policy (Allow Specific)
constraint: constraints/gcp.resourceLocations
listPolicy:
allowedValues:
- "in:us-locations"
- "in:eu-locations"Terraform Resource
resource "google_organization_policy" "example" {
org_id = var.org_id
constraint = "constraints/compute.requireOsLogin"
boolean_policy { enforced = true }
}References
standards.md1.1 KB
Standards and References - GCP Organization Policy Constraints
CIS GCP Foundations Benchmark v3.0
| Section | Control | Constraint |
|---|---|---|
| 1.4 | Ensure user-managed service account keys are rotated within 90 days | iam.disableServiceAccountKeyCreation |
| 3.10 | Ensure VPC Flow Logs are enabled | N/A (use custom constraint) |
| 4.4 | Ensure OS Login is enabled for a project | compute.requireOsLogin |
| 4.5 | Ensure serial port access is disabled | compute.disableSerialPortAccess |
| 6.2 | Ensure Cloud SQL instances are not publicly accessible | sql.restrictPublicIp |
| 5.1 | Ensure uniform bucket-level access is enabled | storage.uniformBucketLevelAccess |
NIST 800-53 Controls Mapping
- AC-3: Access Enforcement
- AC-6: Least Privilege
- CM-7: Least Functionality
- SC-7: Boundary Protection
- SC-12: Cryptographic Key Establishment
Google Cloud Security Best Practices
- Principle of least privilege for organization policies
- Hierarchical policy inheritance model
- Dry-run testing before enforcement
- Separate exception management from baseline policies
workflows.md1.6 KB
Workflows - GCP Organization Policy Constraints
Implementation Workflow
1. Inventory Phase
├── List all existing organization policies
├── Identify current resource configurations
├── Map compliance requirements to constraints
└── Document exceptions needed per team/project
2. Design Phase
├── Select constraints for baseline enforcement
├── Define exception policies for specific folders/projects
├── Plan hierarchy (Org → Folder → Project overrides)
└── Document policy inheritance chain
3. Testing Phase
├── Deploy constraints in dry-run mode
├── Monitor violation logs for 2-4 weeks
├── Identify legitimate use cases requiring exceptions
└── Refine policies based on dry-run results
4. Enforcement Phase
├── Convert dry-run policies to enforced mode
├── Apply exceptions at appropriate hierarchy level
├── Communicate changes to engineering teams
└── Monitor for new violations
5. Ongoing Governance
├── Review policies quarterly
├── Audit exception requests
├── Update constraints for new GCP services
└── Integrate with change management processException Management Workflow
1. Request → Developer requests exception for specific constraint
2. Review → Security team evaluates risk and business justification
3. Approve → Exception approved with scope (project/folder) and duration
4. Implement → Policy override applied at lowest necessary scope
5. Audit → Regular review of active exceptions
6. Expire → Time-bound exceptions automatically revertScripts 2
agent.py7.7 KB
#!/usr/bin/env python3
"""Agent for auditing and managing GCP Organization Policy constraints."""
import json
import argparse
import subprocess
from datetime import datetime
BASELINE_BOOLEAN_CONSTRAINTS = {
"constraints/compute.vmExternalIpAccess": {"type": "list", "expected": "DENY_ALL"},
"constraints/compute.requireOsLogin": {"type": "boolean", "expected": True},
"constraints/compute.disableSerialPortAccess": {"type": "boolean", "expected": True},
"constraints/compute.disableNestedVirtualization": {"type": "boolean", "expected": True},
"constraints/storage.uniformBucketLevelAccess": {"type": "boolean", "expected": True},
"constraints/sql.restrictPublicIp": {"type": "boolean", "expected": True},
"constraints/iam.disableServiceAccountKeyCreation": {"type": "boolean", "expected": True},
"constraints/iam.automaticIamGrantsForDefaultServiceAccounts": {"type": "boolean", "expected": True},
}
def run_gcloud(args_list):
"""Run a gcloud command and return parsed JSON."""
cmd = ["gcloud"] + args_list + ["--format=json"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if result.returncode != 0:
return {"error": result.stderr.strip()}
try:
return json.loads(result.stdout) if result.stdout.strip() else {}
except json.JSONDecodeError:
return {"raw": result.stdout.strip()}
def list_org_policies(org_id):
"""List all active organization policies."""
return run_gcloud(["org-policies", "list", f"--organization={org_id}"])
def describe_policy(org_id, constraint):
"""Get details of a specific org policy constraint."""
return run_gcloud(["org-policies", "describe", constraint,
f"--organization={org_id}"])
def audit_baseline_compliance(org_id):
"""Audit organization against security baseline constraints."""
findings = []
for constraint, expected in BASELINE_BOOLEAN_CONSTRAINTS.items():
policy = describe_policy(org_id, constraint)
if isinstance(policy, dict) and "error" in policy:
findings.append({
"constraint": constraint,
"status": "NOT_SET",
"severity": "HIGH",
"recommendation": f"Enable {constraint}",
})
continue
if expected["type"] == "boolean":
enforced = False
if isinstance(policy, dict):
bp = policy.get("booleanPolicy", {})
enforced = bp.get("enforced", False)
findings.append({
"constraint": constraint,
"status": "COMPLIANT" if enforced else "NON_COMPLIANT",
"severity": "INFO" if enforced else "HIGH",
"current": enforced,
"expected": expected["expected"],
})
elif expected["type"] == "list":
lp = policy.get("listPolicy", {}) if isinstance(policy, dict) else {}
all_denied = lp.get("allValues") == "DENY" or lp.get("deniedValues") == ["*"]
findings.append({
"constraint": constraint,
"status": "COMPLIANT" if all_denied else "NON_COMPLIANT",
"severity": "INFO" if all_denied else "HIGH",
})
return findings
def audit_project_policies(project_id):
"""Audit organization policies effective on a specific project."""
policies = run_gcloud(["org-policies", "list", f"--project={project_id}"])
if isinstance(policies, dict) and "error" in policies:
return [{"error": policies["error"]}]
return policies if isinstance(policies, list) else []
def check_resource_location_constraint(org_id):
"""Check if resource location constraint is configured."""
policy = describe_policy(org_id, "constraints/gcp.resourceLocations")
if isinstance(policy, dict) and "error" not in policy:
lp = policy.get("listPolicy", {})
allowed = lp.get("allowedValues", [])
if allowed:
return {"status": "CONFIGURED", "allowed_locations": allowed}
return {"status": "NOT_CONFIGURED", "severity": "MEDIUM",
"recommendation": "Restrict resource locations to approved regions"}
def generate_terraform_policies(org_id, constraints=None):
"""Generate Terraform HCL for baseline org policies."""
constraints = constraints or list(BASELINE_BOOLEAN_CONSTRAINTS.keys())
tf_blocks = []
for c in constraints:
info = BASELINE_BOOLEAN_CONSTRAINTS.get(c, {"type": "boolean", "expected": True})
resource_name = c.split("/")[1].replace(".", "_")
if info["type"] == "boolean":
tf_blocks.append(f'''resource "google_organization_policy" "{resource_name}" {{
org_id = "{org_id}"
constraint = "{c}"
boolean_policy {{
enforced = true
}}
}}''')
elif info["type"] == "list":
tf_blocks.append(f'''resource "google_organization_policy" "{resource_name}" {{
org_id = "{org_id}"
constraint = "{c}"
list_policy {{
deny {{
all = true
}}
}}
}}''')
return "\n\n".join(tf_blocks)
def generate_compliance_report(findings):
"""Generate a compliance summary from audit findings."""
total = len(findings)
compliant = sum(1 for f in findings if f.get("status") == "COMPLIANT")
non_compliant = sum(1 for f in findings if f.get("status") == "NON_COMPLIANT")
not_set = sum(1 for f in findings if f.get("status") == "NOT_SET")
return {
"total_constraints": total,
"compliant": compliant,
"non_compliant": non_compliant,
"not_set": not_set,
"compliance_percentage": round(compliant / total * 100, 1) if total else 0,
"high_severity_gaps": [f for f in findings if f.get("severity") == "HIGH"],
}
def main():
parser = argparse.ArgumentParser(description="GCP Organization Policy Agent")
parser.add_argument("--org-id", help="GCP organization ID")
parser.add_argument("--project", help="GCP project ID for project-level audit")
parser.add_argument("--action", choices=["audit", "list", "terraform", "locations"],
default="audit")
parser.add_argument("--output", default="gcp_orgpolicy_report.json")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "results": {}}
if args.action == "audit" and args.org_id:
findings = audit_baseline_compliance(args.org_id)
summary = generate_compliance_report(findings)
report["results"]["findings"] = findings
report["results"]["summary"] = summary
print(f"[+] Compliance: {summary['compliance_percentage']}%"
f" ({summary['compliant']}/{summary['total_constraints']})")
elif args.action == "list" and args.org_id:
policies = list_org_policies(args.org_id)
report["results"]["policies"] = policies
count = len(policies) if isinstance(policies, list) else 0
print(f"[+] Active policies: {count}")
elif args.action == "terraform" and args.org_id:
tf = generate_terraform_policies(args.org_id)
report["results"]["terraform"] = tf
print("[+] Terraform configuration generated")
elif args.action == "locations" and args.org_id:
result = check_resource_location_constraint(args.org_id)
report["results"]["location_constraint"] = result
print(f"[+] Location constraint: {result['status']}")
if args.project:
project_policies = audit_project_policies(args.project)
report["results"]["project_policies"] = project_policies
print(f"[+] Project {args.project}: {len(project_policies)} policies")
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()
process.py7.7 KB
#!/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)