npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- Deploying or hardening a Google Workspace environment for enterprise use
- CIS benchmark compliance assessment for Google Workspace configuration
- Protecting against business email compromise (BEC) and phishing attacks targeting Google accounts
- Implementing Data Loss Prevention controls for Gmail and Google Drive
- Restricting OAuth application access and third-party integrations
- Configuring admin account security with Advanced Protection Program enrollment
Do not use for Microsoft 365 environments; Google Workspace has distinct admin console settings and API configurations that differ from Azure AD/Entra ID controls.
Prerequisites
- Google Workspace Business Plus, Enterprise Standard, or Enterprise Plus license
- Super Admin access to the Google Admin Console (admin.google.com)
- DNS management access for SPF, DKIM, and DMARC record configuration
- Google Cloud Identity or Cloud Identity Premium for advanced security features
- FIDO2 security keys for super admin accounts (YubiKey 5 Series recommended)
Workflow
Step 1: Harden Super Admin Accounts
Secure the highest-privilege accounts in the Google Workspace tenant:
# Google Workspace Admin SDK - configure admin account security
# Using gam (Google Apps Manager) CLI tool
# List all super admin accounts for audit
gam print admins role "Super Admin" > super_admins.csv
echo "Review and minimize super admin count (recommended: 2-3 maximum)"
# Enforce Advanced Protection Program for super admins
# APP provides strongest account protections:
# - Requires FIDO2 security key for sign-in
# - Blocks third-party app access to Gmail and Drive
# - Enhanced account recovery verification
gam update user superadmin@corp.com \
advanced_protection true
# Create dedicated break-glass admin account
gam create user breakglass-admin@corp.com \
firstname "Break" lastname "Glass Admin" \
password "$(openssl rand -base64 32)" \
changepassword true \
org "/Emergency Accounts"
# Assign super admin role to break-glass account
gam create admin breakglass-admin@corp.com "Super Admin"
# Configure admin activity alerts
# Alert Center API - create alert for admin actions
cat > admin_alert_policy.json << 'EOF'
{
"alertPolicies": [
{
"name": "Super Admin Sign-In Alert",
"conditions": {
"eventType": "login",
"filterCriteria": "actor.adminRole=SUPER_ADMIN"
},
"notifications": {
"email": ["security-team@corp.com"],
"webhook": "https://siem.corp.com/webhook/google-admin"
}
},
{
"name": "Admin Role Change Alert",
"conditions": {
"eventType": "admin_role_change"
},
"notifications": {
"email": ["security-team@corp.com"]
}
}
]
}
EOFStep 2: Enforce Phishing-Resistant Multi-Factor Authentication
Configure MFA policies that eliminate phishable authentication factors:
# Enforce 2-Step Verification for all organizational units
# Using Admin SDK Directory API
# Enable 2SV enforcement for the entire organization
gam update org "/" settings \
2sv_enforcement true \
2sv_enrollment_grace_period 14 \
2sv_new_user_enrollment_period 1
# Configure allowed 2SV methods - restrict to phishing-resistant only
# For high-security OUs: Security keys only
gam update org "/Executive" settings \
2sv_allowed_methods "SECURITY_KEY_ONLY"
# For general staff: Security keys or phone prompts (no SMS/voice)
gam update org "/" settings \
2sv_allowed_methods "SECURITY_KEY,PHONE_PROMPT" \
2sv_disallowed_methods "SMS,VOICE_CALL,BACKUP_CODES"
# Bulk check 2SV enrollment status
gam print users \
fields primaryEmail,isEnrolledIn2Sv,isEnforcedIn2Sv \
query "isEnrolledIn2Sv=false" > users_without_2sv.csv
# Count users without 2SV
echo "Users without 2SV enrolled:"
wc -l < users_without_2sv.csv
# Configure context-aware access policies
# Require 2SV + managed device for sensitive apps
cat > context_aware_policy.json << 'EOF'
{
"accessLevels": [
{
"name": "Managed Device Required",
"conditions": {
"devicePolicy": {
"requireScreenLock": true,
"requireAdminApproval": true,
"allowedEncryptionStatuses": ["ENCRYPTED"],
"requireCorpOwned": false
},
"requiredAccessLevels": ["VERIFIED_2SV"]
}
}
],
"applicationPolicies": [
{
"applications": ["Google Drive", "Gmail", "Admin Console"],
"accessLevel": "Managed Device Required"
}
]
}
EOFStep 3: Configure Email Authentication and Anti-Phishing
Set up SPF, DKIM, DMARC and advanced phishing protections:
# Step 3a: Configure SPF record
# Add to DNS TXT record for corp.com
echo 'DNS TXT Record for SPF:'
echo 'corp.com TXT "v=spf1 include:_spf.google.com ~all"'
echo ''
echo 'After testing, change ~all to -all (hard fail) for enforcement'
# Step 3b: Generate and configure DKIM signing
# Generate 2048-bit DKIM key via Admin Console or API
gam create dkim domain corp.com selector google bitlength 2048
echo 'Add DKIM DNS TXT record:'
echo 'google._domainkey.corp.com TXT "v=DKIM1; k=rsa; p=<public_key_from_admin_console>"'
# Verify DKIM is working
gam info dkim domain corp.com
# Step 3c: Configure DMARC policy
echo 'DNS TXT Record for DMARC (start with monitoring):'
echo '_dmarc.corp.com TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@corp.com; ruf=mailto:dmarc-forensics@corp.com; pct=100; adkim=s; aspf=s"'
echo ''
echo 'After 30 days monitoring, escalate to quarantine then reject:'
echo '_dmarc.corp.com TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@corp.com; pct=100; adkim=s; aspf=s"'
# Step 3d: Enable advanced phishing and malware protection
# Configure in Admin Console > Security > Email Safety
gam update settings email_safety \
protect_against_domain_spoofing true \
protect_against_employee_spoofing true \
protect_against_inbound_spoofing true \
protect_unauthenticated_email true \
identify_spoofed_groups true \
auto_move_suspicious_to_spam true
# Configure attachment security
gam update settings email_safety \
protect_encrypted_attachments true \
protect_anomalous_attachment_types true \
protect_scripts_from_untrusted true \
whitelist_sender_domains "" \
apply_future_recommended_settings trueStep 4: Implement Data Loss Prevention (DLP)
Configure DLP rules to prevent sensitive data exfiltration:
# Create DLP rules for Gmail and Drive
# Using Google Workspace DLP API
cat > dlp_rules.json << 'EOF'
{
"dlpRules": [
{
"name": "PII Detection - SSN",
"description": "Detect Social Security Numbers in outbound email and Drive sharing",
"trigger": {
"contentMatchers": [
{
"infoType": "US_SOCIAL_SECURITY_NUMBER",
"likelihood": "LIKELY",
"minMatchCount": 1
}
],
"scope": ["GMAIL_OUTBOUND", "DRIVE_EXTERNAL_SHARE"]
},
"action": {
"blockAction": "QUARANTINE",
"notifyAdmin": true,
"notifyUser": true,
"userMessage": "This message contains a Social Security Number and has been quarantined for review.",
"auditLog": true
}
},
{
"name": "Credit Card Number Detection",
"description": "Block credit card numbers in outbound communications",
"trigger": {
"contentMatchers": [
{
"infoType": "CREDIT_CARD_NUMBER",
"likelihood": "LIKELY",
"minMatchCount": 1
}
],
"scope": ["GMAIL_OUTBOUND", "DRIVE_EXTERNAL_SHARE", "CHAT"]
},
"action": {
"blockAction": "BLOCK",
"notifyAdmin": true,
"notifyUser": true,
"auditLog": true
}
},
{
"name": "Confidential Document Detection",
"description": "Detect documents marked as Confidential or Internal Only",
"trigger": {
"contentMatchers": [
{
"customRegex": "(?i)(CONFIDENTIAL|INTERNAL ONLY|DO NOT DISTRIBUTE|RESTRICTED)",
"minMatchCount": 2
}
],
"metadataMatchers": [
{
"driveLabels": ["Confidential", "Restricted"]
}
],
"scope": ["DRIVE_EXTERNAL_SHARE"]
},
"action": {
"blockAction": "WARN",
"requireJustification": true,
"auditLog": true
}
}
]
}
EOF
echo "Apply DLP rules via Admin Console > Security > Data Protection"
echo "Or use the Google Workspace DLP API for programmatic deployment"Step 5: Control OAuth Applications and Third-Party Access
Restrict which third-party applications can access organizational data:
# Configure OAuth app access control
# Admin Console > Security > API Controls > App Access Control
# Block all third-party apps by default, then allowlist approved ones
gam update org "/" settings \
third_party_app_access "BLOCKED" \
allow_users_to_install_apps false
# Allowlist approved applications
cat > approved_apps.json << 'EOF'
{
"allowedApps": [
{
"appId": "slack-app-id",
"name": "Slack",
"scopes": ["gmail.readonly", "calendar.readonly"],
"approvedBy": "security-team",
"reviewDate": "2026-01-15"
},
{
"appId": "zoom-app-id",
"name": "Zoom",
"scopes": ["calendar.events"],
"approvedBy": "security-team",
"reviewDate": "2026-01-15"
},
{
"appId": "salesforce-app-id",
"name": "Salesforce",
"scopes": ["gmail.send", "contacts.readonly"],
"approvedBy": "security-team",
"reviewDate": "2026-01-15"
}
]
}
EOF
# Audit current OAuth tokens granted by users
gam all users print tokens > oauth_tokens_audit.csv
echo "Review oauth_tokens_audit.csv for unauthorized third-party access"
# Revoke tokens for unapproved applications
gam all users deprovision tokens \
clientid "unapproved-app-client-id"
# Configure API scopes restriction
# Limit which API scopes third-party apps can request
gam update org "/" settings \
api_access_restricted true \
allowed_api_scopes "gmail.readonly,calendar.readonly,drive.readonly"Step 6: Configure External Sharing and Drive Security
Lock down data sharing controls:
# Configure Google Drive sharing restrictions
gam update org "/" settings \
drive_sharing_outside_domain "WHITELISTED_DOMAINS" \
drive_sharing_whitelisted_domains "partner1.com,partner2.com" \
drive_allow_file_requests false \
drive_shared_drive_creation "ADMIN_ONLY" \
drive_default_link_sharing "RESTRICTED"
# Configure sharing alerts
gam create alert \
name "External Sharing Alert" \
type "drive_external_share" \
condition "shared_outside_domain=true AND file_type IN ('spreadsheet','document','presentation')" \
action "notify_admin security-team@corp.com"
# Audit current external shares
gam all users print filelist \
fields id,name,owners,permissions \
query "visibility='anyoneWithLink' or visibility='anyoneCanFind'" \
> external_shares_audit.csv
echo "External shares requiring review:"
wc -l < external_shares_audit.csv
# Configure Google Groups security
gam update org "/" settings \
groups_external_members false \
groups_external_posting false \
groups_creation "ADMIN_ONLY" \
groups_allow_external_invitations falseKey Concepts
| Term | Definition |
|---|---|
| Advanced Protection Program (APP) | Google's strongest account security requiring FIDO2 security keys, blocking third-party app access, and enhanced identity verification for account recovery |
| Context-Aware Access | Security policy framework that evaluates device posture, location, and user identity before granting access to Google Workspace applications |
| DMARC | Domain-based Message Authentication, Reporting and Conformance protocol that prevents email domain spoofing by validating SPF and DKIM alignment |
| DLP Rule | Data Loss Prevention policy that scans content in Gmail, Drive, and Chat for sensitive data patterns and triggers block, quarantine, or warn actions |
| OAuth App Allowlisting | Admin control restricting which third-party applications can access organizational data through Google OAuth API scopes |
| 2-Step Verification (2SV) | Google's multi-factor authentication implementation supporting security keys, phone prompts, TOTP, and backup codes as second factors |
Tools & Systems
- Google Admin Console: Web-based administration portal for managing all Google Workspace security settings, users, and organizational units
- GAM (Google Apps Manager): Open-source command-line tool for bulk Google Workspace administration and automation
- Google Workspace Alert Center: Centralized dashboard for security alerts including suspicious login activity, DLP violations, and device compromise
- Google BeyondCorp Enterprise: Zero-trust access solution integrated with Google Workspace for context-aware access policies
Common Scenarios
Scenario: Securing a Newly Acquired Google Workspace Tenant
Context: Post-acquisition security audit reveals the acquired company's Google Workspace has no MFA enforcement, open external sharing, no DLP policies, and multiple unauthorized OAuth applications accessing user data.
Approach:
- Immediately enforce 2SV for all super admin accounts using FIDO2 security keys
- Reduce super admin count to 3 (primary, secondary, break-glass)
- Deploy SPF, DKIM, and DMARC starting with monitoring mode (p=none)
- Enable all anti-phishing and anti-spoofing settings in Email Safety
- Audit and revoke all unauthorized OAuth application tokens
- Set third-party app access to blocked with allowlist of approved applications
- Restrict external Drive sharing to approved partner domains only
- Deploy DLP rules for PII, financial data, and confidential documents
- Enable context-aware access requiring managed devices for sensitive applications
- Configure security alerts and SIEM integration for ongoing monitoring
Pitfalls:
- Enforcing MFA without enrollment grace period locks users out of accounts
- Setting DMARC to reject before monitoring period causes legitimate email delivery failures
- Blocking all OAuth apps without identifying business-critical integrations disrupts workflows
- Not auditing existing external shares before restricting sharing leaves data exposed
Output Format
GOOGLE WORKSPACE SECURITY ASSESSMENT REPORT
=============================================
Tenant: corp.com
License: Enterprise Plus
Total Users: 3,847
Organizational Units: 12
AUTHENTICATION SECURITY
2SV Enforced: YES (all OUs)
2SV Enrollment: 3,712 / 3,847 (96.5%)
Security Keys Only: Executive OU (47 users)
Advanced Protection: 3 super admin accounts
Super Admin Count: 3 (within recommended limit)
EMAIL AUTHENTICATION
SPF: CONFIGURED (hard fail: -all)
DKIM: CONFIGURED (2048-bit, selector: google)
DMARC: ENFORCED (p=reject, 100%)
Anti-Phishing: ALL PROTECTIONS ENABLED
Anti-Spoofing: ENABLED (domain + employee name)
DATA PROTECTION
DLP Rules Active: 7
PII Detection: SSN, Credit Card, Passport
Content Labels: Confidential, Restricted
Custom Patterns: 3 organization-specific rules
DLP Violations (30d): 89 (67 blocked, 22 warned)
APPLICATION CONTROL
Third-Party App Policy: BLOCKED (allowlist mode)
Approved Apps: 12
Unauthorized Tokens: 0 (all revoked)
API Scope Restrictions: ENABLED
SHARING CONTROLS
External Sharing: RESTRICTED (allowlisted domains only)
Public Link Sharing: DISABLED
External Group Members: DISABLED
Shared Drive Creation: ADMIN ONLYReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.2 KB
API Reference: Implementing Google Workspace Admin Security
Libraries
google-api-python-client + google-auth
- Install:
pip install google-api-python-client google-auth - Docs: https://developers.google.com/admin-sdk/directory/reference/rest
Admin SDK Directory API
| Method | Description |
|---|---|
users().list(domain, projection="full") |
List users with full profile |
users().get(userKey) |
Get specific user details |
users().update(userKey, body) |
Update user settings |
users().list(query="isAdmin=true") |
List admin users |
orgunits().list(customerId) |
List organizational units |
roles().list(customer) |
List admin roles |
roleAssignments().list(customer) |
List role assignments |
Reports API (Audit Logs)
| Method | Description |
|---|---|
activities().list(userKey, applicationName) |
Get audit events |
Application names: login, admin, drive, token, mobile |
Key User Fields for Security
| Field | Description |
|---|---|
isEnrolledIn2Sv |
User enrolled in 2-Step Verification |
isEnforcedIn2Sv |
2SV enforcement applied |
isAdmin |
Super admin status |
isDelegatedAdmin |
Delegated admin status |
lastLoginTime |
Last login timestamp |
recoveryEmail |
Recovery email (risk if external) |
recoveryPhone |
Recovery phone number |
isSuspended |
Account suspended |
OAuth Scopes Required
admin.directory.user-- User managementadmin.directory.domain-- Domain settingsadmin.reports.audit.readonly-- Audit log accessadmin.directory.orgunit-- Org unit management
Login Event Names
login_success-- Successful loginlogin_failure-- Failed login attemptlogin_challenge-- 2FA challenge issuedsuspicious_login-- Flagged by Googleaccount_disabled_password_leak-- Compromised password
External References
- Admin SDK: https://developers.google.com/admin-sdk
- Workspace Security Best Practices: https://support.google.com/a/answer/7587183
- CIS Google Workspace Benchmark: https://www.cisecurity.org/benchmark/google_workspace
- Reports API: https://developers.google.com/admin-sdk/reports/reference/rest
Scripts 1
agent.py8.3 KB
#!/usr/bin/env python3
"""Google Workspace admin security hardening agent using Admin SDK."""
import json
import sys
import argparse
from datetime import datetime
try:
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
except ImportError:
print("Install: pip install google-api-python-client google-auth")
sys.exit(1)
SCOPES = [
"https://www.googleapis.com/auth/admin.directory.user",
"https://www.googleapis.com/auth/admin.directory.domain",
"https://www.googleapis.com/auth/admin.reports.audit.readonly",
"https://www.googleapis.com/auth/admin.directory.orgunit",
]
def get_admin_service(credentials_file, admin_email, api="admin", version="directory_v1"):
"""Build Google Admin SDK service with domain-wide delegation."""
creds = service_account.Credentials.from_service_account_file(
credentials_file, scopes=SCOPES, subject=admin_email)
return build(api, version, credentials=creds)
def get_reports_service(credentials_file, admin_email):
"""Build Reports API service."""
creds = service_account.Credentials.from_service_account_file(
credentials_file, scopes=SCOPES, subject=admin_email)
return build("admin", "reports_v1", credentials=creds)
def list_users_without_2fa(service, domain):
"""List users who have not enrolled in 2-Step Verification."""
users_without_2fa = []
request = service.users().list(domain=domain, maxResults=500,
projection="full", orderBy="email")
while request:
response = request.execute()
for user in response.get("users", []):
is_enrolled = user.get("isEnrolledIn2Sv", False)
is_enforced = user.get("isEnforcedIn2Sv", False)
if not is_enrolled:
users_without_2fa.append({
"email": user["primaryEmail"],
"name": user.get("name", {}).get("fullName", ""),
"is_admin": user.get("isAdmin", False),
"is_2sv_enrolled": is_enrolled,
"is_2sv_enforced": is_enforced,
"last_login": user.get("lastLoginTime", "never"),
})
request = service.users().list_next(request, response)
return users_without_2fa
def list_admin_users(service, domain):
"""List all admin users and their admin roles."""
admins = []
request = service.users().list(domain=domain, maxResults=500,
projection="full", query="isAdmin=true")
response = request.execute()
for user in response.get("users", []):
admins.append({
"email": user["primaryEmail"],
"name": user.get("name", {}).get("fullName", ""),
"is_super_admin": user.get("isAdmin", False),
"is_delegated_admin": user.get("isDelegatedAdmin", False),
"is_2sv_enrolled": user.get("isEnrolledIn2Sv", False),
"last_login": user.get("lastLoginTime", "never"),
"creation_time": user.get("creationTime", ""),
})
return admins
def get_login_audit_events(reports_service, user_email=None, days=7):
"""Get login audit events to detect suspicious activity."""
events = []
try:
params = {"userKey": "all", "applicationName": "login", "maxResults": 200}
if user_email:
params["userKey"] = user_email
request = reports_service.activities().list(**params)
response = request.execute()
for activity in response.get("items", []):
for event in activity.get("events", []):
event_data = {
"user": activity.get("actor", {}).get("email", ""),
"event_name": event.get("name", ""),
"time": activity.get("id", {}).get("time", ""),
"ip_address": activity.get("ipAddress", ""),
}
for param in event.get("parameters", []):
event_data[param["name"]] = param.get("value", param.get("boolValue", ""))
events.append(event_data)
except HttpError as e:
events.append({"error": str(e)})
return events
def check_suspended_users(service, domain):
"""List suspended users that may still have active sessions."""
suspended = []
request = service.users().list(domain=domain, maxResults=500,
query="isSuspended=true")
response = request.execute()
for user in response.get("users", []):
suspended.append({
"email": user["primaryEmail"],
"suspension_reason": user.get("suspensionReason", "manual"),
"last_login": user.get("lastLoginTime", "never"),
})
return suspended
def check_recovery_settings(service, domain):
"""Audit users with recovery email/phone that could be used for account takeover."""
findings = []
request = service.users().list(domain=domain, maxResults=500, projection="full")
response = request.execute()
for user in response.get("users", []):
recovery_email = user.get("recoveryEmail", "")
recovery_phone = user.get("recoveryPhone", "")
if user.get("isAdmin") and (recovery_email or recovery_phone):
if recovery_email and not recovery_email.endswith(f"@{domain}"):
findings.append({
"email": user["primaryEmail"],
"issue": "Admin has external recovery email",
"recovery_email": recovery_email,
"severity": "HIGH",
})
return findings
def run_workspace_audit(service, reports_service, domain):
"""Run comprehensive Google Workspace security audit."""
print(f"\n{'='*60}")
print(f" GOOGLE WORKSPACE SECURITY AUDIT")
print(f" Domain: {domain}")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
admins = list_admin_users(service, domain)
print(f"--- ADMIN ACCOUNTS ({len(admins)}) ---")
for a in admins:
mfa_status = "2FA ON" if a["is_2sv_enrolled"] else "2FA OFF"
print(f" [{mfa_status}] {a['email']} (Super: {a['is_super_admin']})")
no_2fa = list_users_without_2fa(service, domain)
print(f"\n--- USERS WITHOUT 2FA ({len(no_2fa)}) ---")
admin_no_2fa = [u for u in no_2fa if u["is_admin"]]
if admin_no_2fa:
print(f" CRITICAL: {len(admin_no_2fa)} admin(s) without 2FA!")
for u in admin_no_2fa:
print(f" {u['email']}")
print(f" Total users without 2FA: {len(no_2fa)}")
recovery = check_recovery_settings(service, domain)
print(f"\n--- RECOVERY SETTINGS ISSUES ({len(recovery)}) ---")
for r in recovery:
print(f" [{r['severity']}] {r['email']}: {r['issue']}")
suspended = check_suspended_users(service, domain)
print(f"\n--- SUSPENDED USERS ({len(suspended)}) ---")
for s in suspended[:5]:
print(f" {s['email']} (Reason: {s['suspension_reason']})")
events = get_login_audit_events(reports_service)
suspicious = [e for e in events if e.get("event_name") == "login_failure"]
print(f"\n--- RECENT LOGIN EVENTS ---")
print(f" Total events: {len(events)}")
print(f" Failed logins: {len(suspicious)}")
print(f"\n{'='*60}\n")
return {"admins": len(admins), "no_2fa": len(no_2fa),
"admin_no_2fa": len(admin_no_2fa), "suspended": len(suspended)}
def main():
parser = argparse.ArgumentParser(description="Google Workspace Admin Security Agent")
parser.add_argument("--credentials", required=True, help="Service account JSON key file")
parser.add_argument("--admin-email", required=True, help="Admin email for delegation")
parser.add_argument("--domain", required=True, help="Google Workspace domain")
parser.add_argument("--audit", action="store_true", help="Run full security audit")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.audit:
service = get_admin_service(args.credentials, args.admin_email)
reports = get_reports_service(args.credentials, args.admin_email)
report = run_workspace_audit(service, reports, args.domain)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
else:
parser.print_help()
if __name__ == "__main__":
main()