v0.1.0-draft AI Drafted

Google Workspace Hardening Guide

Productivity Last updated: 2025-02-05

Comprehensive security hardening for Google Workspace, Gmail, Drive, and Google Admin Console

Overview

Google Workspace is used by over 9 million organizations worldwide for email, document collaboration, and cloud storage. As a primary target for phishing and credential theft, Google Workspace security is critical—phishing was responsible for financially devastating data breaches for 9/10 organizations in 2024. According to CISA, accounts with MFA enabled are 99% less likely to be compromised.

Intended Audience

  • Security engineers managing Google Workspace environments
  • IT administrators configuring Admin Console security
  • GRC professionals assessing cloud productivity compliance
  • Third-party risk managers evaluating Google integrations

How to Use This Guide

  • L1 (Baseline): Essential controls for all organizations
  • L2 (Hardened): Enhanced controls for security-sensitive environments
  • L3 (Maximum Security): Strictest controls for regulated industries

Scope

This guide covers Google Workspace Admin Console security configurations including authentication policies, OAuth app controls, Drive sharing settings, Gmail protection, and device management. Google Cloud Platform (GCP) infrastructure is covered in a separate guide.


Table of Contents

  1. Authentication & Access Controls
  2. Network Access Controls
  3. OAuth & Integration Security
  4. Data Security
  5. Monitoring & Detection
  6. Third-Party Integration Security
  7. Compliance Quick Reference

1. Authentication & Access Controls

1.1 Enforce Multi-Factor Authentication for All Users

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 6.3, 6.5
NIST 800-53 IA-2(1), IA-2(6)
CIS Google Workspace 1.1

Description

Require 2-Step Verification (2SV) for all users with enforcement, not just enrollment. Microsoft found that enabling MFA prevents 99.9% of automated attacks on cloud accounts.

Rationale

Why This Matters:

  • Phishing remains the #1 attack vector against Google Workspace
  • Password reuse and credential stuffing are common attack methods
  • Accounts with MFA are 99% less likely to be compromised (CISA)

Attack Prevented: Credential theft, phishing, password spray, account takeover

Real-World Incidents:

  • Twitter (2020): Compromised employee credentials led to high-profile account takeover
  • Colonial Pipeline (2021): VPN credentials without MFA enabled ransomware deployment

Prerequisites

  • Super Admin access to Google Admin Console
  • User communication plan for 2SV enrollment
  • Security keys for privileged users (recommended)

ClickOps Implementation

Step 1: Enable 2-Step Verification Enrollment

  1. Navigate to: Admin ConsoleSecurityAuthentication2-Step Verification
  2. Check Allow users to turn on 2-Step Verification
  3. Set Enforcement to On for all organizational units
  4. Configure New user enrollment period: 7 days (grace period)
  5. Click Save

Step 2: Configure Allowed Methods

  1. In the same section, click Allowed methods
  2. Select Any except verification codes via text or phone call (recommended)
  3. This forces users to use authenticator apps or security keys instead of vulnerable SMS

Step 3: Enforce Security Keys for Admins

  1. Navigate to: SecurityAuthentication2-Step Verification
  2. Select the Admin organizational unit
  3. Set Allowed methods to Only security key
  4. Click Save

Time to Complete: ~30 minutes

Code Implementation

Validation & Testing

How to verify the control is working:

  1. Sign in as test user - 2SV prompt should appear
  2. Check Admin Console → Reports → User Reports → Security
  3. Verify 2SV enrollment percentage approaches 100%
  4. Attempt sign-in with only password - should fail after enforcement

Expected result: All users prompted for second factor, enforcement active

Monitoring & Maintenance

Ongoing monitoring:

  • Monitor Security → Investigation Tool for failed 2SV attempts
  • Alert on suspicious sign-in attempts
  • Track 2SV enrollment completion

Admin Console Query: Navigate to Security, then Investigation Tool. Set Event to Login, and filter by 2SV method = None, Login result = Success.

Maintenance schedule:

  • Weekly: Review new user 2SV enrollment
  • Monthly: Audit 2SV enforcement exceptions
  • Quarterly: Review and rotate Super Admin security keys

Operational Impact

Aspect Impact Level Details
User Experience Low-Medium Initial enrollment required; subsequent logins add ~5 seconds
System Performance None No performance impact
Maintenance Burden Low Minimal after initial rollout
Rollback Difficulty Easy Disable enforcement in Admin Console

Potential Issues:

  • Users without smartphones: Provide hardware security keys
  • Shared device environments: Use security keys instead of mobile apps

Rollback Procedure:

  1. Navigate to Admin Console → Security → 2-Step Verification
  2. Set Enforcement to Off
  3. Note: This leaves accounts vulnerable; use only for emergency troubleshooting

Compliance Mappings

Framework Control ID Control Description
SOC 2 CC6.1 Logical access security
NIST 800-53 IA-2(1) Multi-factor authentication
ISO 27001 A.9.4.2 Secure log-on procedures
CIS Google Workspace 1.1 Ensure 2-Step Verification is enforced
Code Pack: Terraform
hth-google-workspace-1.01-enforce-mfa.tf View source on GitHub ↗
# Retrieve all users to audit 2SV enrollment status.
# The googleworkspace provider does not expose a direct 2SV enforcement toggle;
# enforcement is configured via Admin Console or GAM.  This data source lets
# Terraform surface enrollment gaps so you can detect non-compliant users.

data "googleworkspace_users" "all" {
  filter = "isEnrolledIn2Sv=false"
}

# Create a dedicated OU for users who must complete 2SV enrollment.
# Moving users into this OU lets you apply stricter policies (e.g., security-
# key-only) via Admin Console while tracking the OU in Terraform state.
resource "googleworkspace_org_unit" "mfa_enforcement" {
  name                 = "MFA Enforcement"
  description          = "HTH 1.1 -- Users in this OU are subject to 2SV enforcement policies"
  parent_org_unit_path = var.target_org_unit_path
}

# Create an OU for Super Admins who require security-key-only 2SV (L3).
resource "googleworkspace_org_unit" "super_admin_mfa" {
  count = var.profile_level >= 3 ? 1 : 0

  name                 = "Super Admins - Security Key Only"
  description          = "HTH 1.1 L3 -- Super Admins restricted to hardware security keys"
  parent_org_unit_path = var.target_org_unit_path
}

# Group for tracking users who have NOT enrolled in 2SV.
# Membership is managed outside Terraform (via GAM or Admin SDK scripts) but
# having the group in state ensures it exists and can be referenced by alerts.
resource "googleworkspace_group" "mfa_not_enrolled" {
  email       = "mfa-not-enrolled@${var.primary_domain}"
  name        = "MFA Not Enrolled"
  description = "HTH 1.1 -- Users who have not yet enrolled in 2-Step Verification. Auto-populated by audit scripts."
}
Code Pack: CLI Script
hth-google-workspace-1.01-check-2sv-enrollment.sh View source on GitHub ↗
# List users not enrolled in 2SV
gam print users query "isEnrolledIn2Sv=false"

# Generate report of 2SV status
gam report users parameters accounts:is_2sv_enrolled,accounts:is_2sv_enforced

# Send reminder to users not enrolled
gam print users query "isEnrolledIn2Sv=false" | \
  gam csv - gam user ~primaryEmail sendemail subject "MFA Enrollment Required" \
  message "Please enroll in 2-Step Verification within 7 days."
# Admin Console monitoring query for users without 2SV
# Navigate to: Security → Investigation Tool
# Event: Login
# Filter: 2SV method = None, Login result = Success
Code Pack: SDK Script
hth-google-workspace-1.01-check-2sv-enrollment.py View source on GitHub ↗
# Enable 2SV enforcement via Admin SDK
from googleapiclient.discovery import build
from google.oauth2 import service_account

SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']
SERVICE_ACCOUNT_FILE = 'service-account.json'

credentials = service_account.Credentials.from_service_account_file(
    SERVICE_ACCOUNT_FILE, scopes=SCOPES)
credentials = credentials.with_subject('admin@yourdomain.com')

service = build('admin', 'directory_v1', credentials=credentials)

# Check 2SV enrollment status for users
results = service.users().list(
    customer='my_customer',
    maxResults=100,
    orderBy='email',
    projection='full'
).execute()

users = results.get('users', [])
for user in users:
    email = user['primaryEmail']
    is_enrolled = user.get('isEnrolledIn2Sv', False)
    is_enforced = user.get('isEnforcedIn2Sv', False)
    print(f"{email}: Enrolled={is_enrolled}, Enforced={is_enforced}")

1.2 Restrict Super Admin Account Usage

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 5.4
NIST 800-53 AC-6(1), AC-6(5)
CIS Google Workspace 1.2

Description

Limit Super Admin privileges to 2-4 dedicated accounts, enforce security keys for authentication, and use delegated admin roles for day-to-day administration.

Rationale

Why This Matters:

  • Super Admin accounts have unrestricted access to all data and settings
  • Compromised Super Admin = complete organization compromise
  • Delegated roles follow principle of least privilege

Attack Prevented: Privilege escalation, lateral movement, admin account compromise

Prerequisites

  • Inventory of current Super Admin accounts
  • Security keys for all Super Admins
  • Defined delegated admin roles

ClickOps Implementation

Step 1: Audit Current Super Admins

  1. Navigate to: Admin ConsoleAccountAdmin roles
  2. Click Super Admin role
  3. Review assigned users - should be 2-4 maximum
  4. Document and remove unnecessary assignments

Step 2: Create Delegated Admin Roles

  1. Navigate to: Admin ConsoleAccountAdmin roles
  2. Click Create new role
  3. Create role-specific admins:
    • User Admin: Manage users, reset passwords
    • Groups Admin: Manage groups and memberships
    • Help Desk Admin: Reset passwords, view user info
  4. Assign appropriate permissions for each role

Step 3: Enforce Security Keys for Super Admins

  1. Create organizational unit: Super Admins
  2. Move Super Admin accounts to this OU
  3. Navigate to: Security2-Step Verification
  4. Select Super Admins OU
  5. Set Allowed methods to Only security key

Time to Complete: ~45 minutes

Code Implementation

Validation & Testing

  1. Verify only 2-4 Super Admin accounts exist
  2. Confirm all Super Admins use security keys
  3. Test delegated admin can perform assigned tasks only
  4. Verify delegated admin cannot access Super Admin functions
Code Pack: Terraform
hth-google-workspace-1.02-restrict-super-admin.tf View source on GitHub ↗
# Create delegated admin roles following the principle of least privilege.
# Super Admin accounts should be limited to 2-4; day-to-day admin tasks
# should use these scoped roles instead.

resource "googleworkspace_role" "user_admin" {
  name        = "HTH User Administrator"
  description = "HTH 1.2 -- Delegated role for user management (password resets, profile updates)"

  privileges {
    service_id = "00haapch16h1ysv"  # Admin SDK - Users
    privilege  = "USERS_RETRIEVE"
  }
  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "USERS_UPDATE"
  }
  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "USERS_ALIAS"
  }
}

resource "googleworkspace_role" "groups_admin" {
  name        = "HTH Groups Administrator"
  description = "HTH 1.2 -- Delegated role for group management (create, update, membership)"

  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "GROUPS_RETRIEVE"
  }
  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "GROUPS_UPDATE"
  }
}

resource "googleworkspace_role" "help_desk_admin" {
  name        = "HTH Help Desk Administrator"
  description = "HTH 1.2 -- Delegated role for help desk (password resets, view user info)"

  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "USERS_RETRIEVE"
  }
  privileges {
    service_id = "00haapch16h1ysv"
    privilege  = "USERS_UPDATE"
  }
}

# Create custom delegated roles from variable input
resource "googleworkspace_role" "custom" {
  for_each = var.delegated_admin_roles

  name        = each.key
  description = each.value.description

  dynamic "privileges" {
    for_each = each.value.privileges
    content {
      service_id = privileges.value.service_id
      privilege  = privileges.value.privilege
    }
  }
}

# Create an OU for Super Admin accounts so security-key-only 2SV
# can be applied at the OU level via Admin Console.
resource "googleworkspace_org_unit" "super_admins" {
  name                 = "Super Admins"
  description          = "HTH 1.2 -- Dedicated OU for Super Admin accounts with security-key-only 2SV"
  parent_org_unit_path = var.target_org_unit_path
}

# Group for auditing Super Admin role holders.
# Membership should be manually managed and kept to 2-4 accounts.
resource "googleworkspace_group" "super_admin_audit" {
  email       = "super-admin-audit@${var.primary_domain}"
  name        = "Super Admin Audit"
  description = "HTH 1.2 -- Tracks Super Admin role holders. Should contain 2-4 members maximum."
}
Code Pack: CLI Script
hth-google-workspace-1.02-manage-admin-roles.sh View source on GitHub ↗
# List all Super Admins
gam print admins role "Super Admin"

# Create delegated admin role
gam create adminrole "Help Desk Admin" privileges \
  USERS_RETRIEVE,USERS_UPDATE,USERS_ALIAS

# Assign delegated role
gam create admin user helpdesk@domain.com role "Help Desk Admin"

# Remove Super Admin from non-essential users
gam delete admin user bob@domain.com role "Super Admin"

1.3 Configure Context-Aware Access

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 6.4, 13.5
NIST 800-53 AC-2(11), AC-6(1)

Description

Implement context-aware access policies that evaluate device, location, and user risk before granting access to Google Workspace applications.

Rationale

Why This Matters:

  • Allows enforcement of device compliance before access
  • Can block access from high-risk locations
  • Provides additional layer beyond authentication

Prerequisites

  • Google Workspace Enterprise Standard or Plus
  • BeyondCorp Enterprise (for advanced features)
  • Endpoint Verification deployed to managed devices

ClickOps Implementation

Step 1: Deploy Endpoint Verification

  1. Navigate to: Admin ConsoleDevicesMobile & endpointsSettings
  2. Enable Endpoint Verification
  3. Deploy Chrome extension to managed devices
  4. Or use Google’s Endpoint Verification app for unmanaged devices

Step 2: Create Access Level

  1. Navigate to: SecurityAccess and data controlContext-Aware Access
  2. Click Access LevelsCreate Access Level
  3. Configure conditions:
    • Device must have Endpoint Verification
    • Device must be encrypted
    • Device must have screen lock
  4. Save access level

Step 3: Assign Access Level to Apps

  1. In Context-Aware Access, click Assign Access Levels
  2. Select apps (Gmail, Drive, etc.)
  3. Assign the created access level
  4. Enable enforcement after testing

Time to Complete: ~1 hour

Code Implementation

Code Pack: Terraform
hth-google-workspace-1.03-configure-context-aware-access.tf View source on GitHub ↗
# Context-Aware Access requires Google Workspace Enterprise Standard/Plus
# and uses Access Context Manager (part of BeyondCorp Enterprise).

# Access policy -- one per organization.  If you already have an access
# policy, import it rather than creating a new one.
resource "google_access_context_manager_access_policy" "workspace" {
  count = var.profile_level >= 2 && var.organization_id != "" ? 1 : 0

  parent = "organizations/${var.organization_id}"
  title  = var.access_policy_name
}

# Access level: require managed device with Endpoint Verification,
# disk encryption, and screen lock.
resource "google_access_context_manager_access_level" "managed_device" {
  count = var.profile_level >= 2 && var.organization_id != "" ? 1 : 0

  parent = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}/accessLevels/hth_managed_device"
  title  = "HTH Managed Device"

  basic {
    conditions {
      device_policy {
        require_screen_lock              = true
        allowed_encryption_statuses      = ["ENCRYPTED"]
        require_admin_approval           = false
        require_corp_owned               = false
        allowed_device_management_levels = ["BASIC", "COMPLETE"]
      }
    }
  }
}

# L3: Stricter access level requiring corporate-owned, fully managed devices
resource "google_access_context_manager_access_level" "corp_device" {
  count = var.profile_level >= 3 && var.organization_id != "" ? 1 : 0

  parent = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}/accessLevels/hth_corp_device"
  title  = "HTH Corporate-Owned Device"

  basic {
    conditions {
      device_policy {
        require_screen_lock              = true
        allowed_encryption_statuses      = ["ENCRYPTED"]
        require_admin_approval           = true
        require_corp_owned               = true
        allowed_device_management_levels = ["COMPLETE"]
      }
    }
  }
}

2. Network Access Controls

2.1 Configure Allowed IP Ranges for Admin Console

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 13.5
NIST 800-53 AC-17, SC-7

Description

Restrict Admin Console access to specific IP ranges (corporate network, VPN) to prevent unauthorized administrative access.

ClickOps Implementation

Step 1: Configure Allowed IPs

  1. Navigate to: Admin ConsoleSecurityAccess and data controlContext-Aware Access
  2. Create access level with IP conditions
  3. Specify corporate egress IP ranges
  4. Apply to Admin Console access

Step 2: Alternative - Session Control

  1. Navigate to: SecurityGoogle Cloud session control
  2. Configure reauthentication frequency for sensitive apps

Code Implementation

Code Pack: Terraform
hth-google-workspace-2.01-restrict-admin-ip-ranges.tf View source on GitHub ↗
# Restrict Admin Console access to known corporate IP ranges.
# Uses Access Context Manager to create an IP-based access level that
# can be applied to Admin Console and other sensitive applications.

resource "google_access_context_manager_access_level" "admin_ip_allowlist" {
  count = var.profile_level >= 2 && length(var.admin_allowed_cidrs) > 0 && var.organization_id != "" ? 1 : 0

  parent = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}/accessLevels/hth_admin_ip_allowlist"
  title  = "HTH Admin Console IP Allowlist"

  basic {
    conditions {
      ip_subnetworks = var.admin_allowed_cidrs
    }
  }
}

# L3: Combine IP restriction with managed device requirement
resource "google_access_context_manager_access_level" "admin_ip_and_device" {
  count = var.profile_level >= 3 && length(var.admin_allowed_cidrs) > 0 && var.organization_id != "" ? 1 : 0

  parent = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.workspace[0].name}/accessLevels/hth_admin_ip_and_device"
  title  = "HTH Admin Console IP + Device"

  basic {
    combining_function = "AND"

    conditions {
      ip_subnetworks = var.admin_allowed_cidrs
    }

    conditions {
      device_policy {
        require_screen_lock              = true
        allowed_encryption_statuses      = ["ENCRYPTED"]
        require_corp_owned               = true
        allowed_device_management_levels = ["COMPLETE"]
      }
    }
  }
}

3. OAuth & Integration Security

3.1 Enable OAuth App Whitelisting

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 2.5
NIST 800-53 AC-3, CM-7
CIS Google Workspace 2.1

Description

Restrict which third-party applications can access Google Workspace data via OAuth. Block unverified apps and require admin approval for new integrations.

Rationale

Why This Matters:

  • OAuth consent phishing is a growing attack vector
  • Malicious apps can gain persistent access to email and files
  • Users often grant excessive permissions without understanding risks

Attack Prevented: OAuth consent phishing, malicious app installation, data exfiltration

Real-World Incidents:

  • Google Docs Phishing (2017): Fake “Google Docs” app tricked users into granting email access
  • Multiple incidents of data-stealing apps masquerading as productivity tools

Prerequisites

  • Inventory of currently authorized OAuth apps
  • Business justification for each approved app
  • User communication about approval process

ClickOps Implementation

Step 1: Review Current OAuth Apps

  1. Navigate to: Admin ConsoleSecurityAPI controlsApp access control
  2. Click Manage Third-Party App Access
  3. Review list of apps with access to organizational data
  4. Document apps that should be allowed

Step 2: Configure App Whitelisting

  1. In App access control, click Settings
  2. Set default policy: Block all third-party API access or Block unconfigured third-party apps
  3. Configure trusted apps list
  4. Click Save

Step 3: Whitelist Approved Apps

  1. Click Add appOAuth App Name or Client ID
  2. Search for app or enter Client ID
  3. Configure access level:
    • Trusted: Full access to requested scopes
    • Limited: Access to only non-sensitive scopes
    • Blocked: No access
  4. Add business justification
  5. Click Configure

Time to Complete: ~1 hour (initial configuration), ongoing for new app requests

Code Implementation

Validation & Testing

  1. Verify blocked apps cannot access data
  2. Test app approval workflow
  3. Review Security Investigation Tool for blocked app attempts
  4. Confirm whitelisted apps function correctly

Expected result: Only approved apps can access organizational data

Compliance Mappings

Framework Control ID Control Description
SOC 2 CC6.1 Logical access security
NIST 800-53 AC-3 Access enforcement
CIS Google Workspace 2.1 Ensure third-party apps are audited and controlled
Code Pack: Terraform
hth-google-workspace-3.01-enable-oauth-app-whitelisting.tf View source on GitHub ↗
# The googleworkspace provider does not directly manage the OAuth app
# allowlist/blocklist setting.  These resources create the organizational
# infrastructure for OAuth governance:
#
# 1. A group to track approved apps and their owners
# 2. An OU for users with restricted OAuth access
# 3. Documentation of the manual Admin Console steps required
#
# Full API-level control requires GAM or the Admin SDK.

# Group for OAuth app governance -- members are app owners/reviewers
resource "googleworkspace_group" "oauth_reviewers" {
  email       = "oauth-app-reviewers@${var.primary_domain}"
  name        = "OAuth App Reviewers"
  description = "HTH 3.1 -- Members review and approve third-party OAuth app requests"
}

# Group to receive notifications about blocked OAuth app access attempts
resource "googleworkspace_group" "oauth_blocked_alerts" {
  email       = "oauth-blocked-alerts@${var.primary_domain}"
  name        = "OAuth Blocked App Alerts"
  description = "HTH 3.1 -- Receives alerts when users attempt to authorize blocked OAuth apps"
}

# OU for users with strictly no third-party OAuth access (high-security users)
resource "googleworkspace_org_unit" "oauth_restricted" {
  count = var.profile_level >= 2 ? 1 : 0

  name                 = "OAuth Restricted Users"
  description          = "HTH 3.1 L2 -- Users in this OU cannot authorize any third-party OAuth apps"
  parent_org_unit_path = var.target_org_unit_path
}

# Retrieve the domain to verify it exists before creating domain-level resources
data "googleworkspace_domain" "primary" {
  domain_name = var.primary_domain
}
Code Pack: CLI Script
hth-google-workspace-3.01-audit-oauth-apps.sh View source on GitHub ↗
# List all OAuth tokens in use
gam all users print tokens

# List apps with specific scopes
gam all users print tokens scopes "https://mail.google.com/"

# Revoke tokens for specific app
gam all users deprovision token clientid 1234567890.apps.googleusercontent.com

# Block unverified apps (via Admin SDK)
# Note: Use Admin Console for comprehensive control
Code Pack: SDK Script
hth-google-workspace-3.01-list-oauth-tokens.py View source on GitHub ↗
# List OAuth tokens for a user
from googleapiclient.discovery import build

service = build('admin', 'directory_v1', credentials=credentials)

tokens = service.tokens().list(userKey='user@domain.com').execute()

for token in tokens.get('items', []):
    print(f"App: {token['displayText']}")
    print(f"Client ID: {token['clientId']}")
    print(f"Scopes: {token['scopes']}")
    print("---")

3.2 Disable Less Secure Apps

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 4.2
NIST 800-53 IA-2

Description

Disable “Less Secure Apps” access which allows applications to authenticate with just username/password, bypassing 2-Step Verification.

Rationale

Why This Matters:

  • Less Secure Apps bypass MFA completely
  • Legacy protocols are targets for password spray
  • Google has deprecated this feature, but some tenants may still have it enabled

ClickOps Implementation

Step 1: Disable Less Secure Apps

  1. Navigate to: Admin ConsoleSecurityLess secure apps
  2. Select Disable access to less secure apps (Recommended)
  3. Click Save

Note: This should be disabled by default for most tenants as of recent Google updates.

Code Implementation

Code Pack: Terraform
hth-google-workspace-3.02-disable-less-secure-apps.tf View source on GitHub ↗
# "Less Secure Apps" allow authentication with username/password only,
# completely bypassing 2-Step Verification.  Google has deprecated this
# feature but some legacy tenants may still have it enabled.
#
# The googleworkspace provider does not expose a direct toggle for the
# organization-wide "Less Secure Apps" setting.  This control creates
# the organizational structure to enforce the policy:
#
# 1. An OU for legacy app users who temporarily need access (with
#    an expiration plan)
# 2. A tracking group for audit and remediation
#
# Enforcement is done via:
#   Admin Console > Security > Less secure apps > Disable access (Recommended)
#
# Or via GAM:
#   gam ou / update less_secure_apps DISABLED

# Tracking group for applications still requiring less-secure-app access.
# This group should be empty -- any members represent technical debt.
resource "googleworkspace_group" "legacy_app_tracking" {
  email       = "legacy-app-tracking@${var.primary_domain}"
  name        = "Legacy App Tracking"
  description = "HTH 3.2 -- Tracks applications requiring less-secure-app access. Target: zero members."
}

# Temporary OU for users who need transitional legacy app access.
# Should be emptied and removed within 90 days.
resource "googleworkspace_org_unit" "legacy_app_exception" {
  count = var.profile_level >= 1 ? 1 : 0

  name                 = "Legacy App Exceptions"
  description          = "HTH 3.2 -- Temporary OU for users needing legacy app access. Must be emptied within 90 days."
  parent_org_unit_path = var.target_org_unit_path
}

4. Data Security

4.1 Configure External Drive Sharing Restrictions

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 3.3
NIST 800-53 AC-3, AC-22
CIS Google Workspace 3.1

Description

Restrict external sharing of Google Drive files to prevent unauthorized data exposure. Configure default sharing settings to “Restricted” and control “Anyone with the link” sharing.

Rationale

Why This Matters:

  • Oversharing is one of the biggest security risks in Google Workspace
  • “Anyone with the link” files can be accessed by anyone who discovers the URL
  • Data exposure from misconfigured sharing is common

Attack Prevented: Data exfiltration, accidental data exposure, insider threats

Prerequisites

  • Inventory of current sharing policies
  • Business requirements for external collaboration

ClickOps Implementation

Step 1: Configure Organization-Wide Sharing

  1. Navigate to: Admin ConsoleAppsGoogle WorkspaceDrive and Docs
  2. Click Sharing settings
  3. Configure Sharing options:
    • Sharing outside of [organization]: Off or Allowlisted domains only
    • Default link sharing: Restricted (only people added)
  4. Click Save

Step 2: Configure Sharing for Specific OUs

  1. Select organizational unit from left panel
  2. Override settings for teams requiring external collaboration
  3. Use most restrictive settings possible

Step 3: Disable “Anyone with the link”

  1. In Sharing settings, find Link sharing default
  2. Set to Restricted (not “Anyone with the link”)
  3. Optionally block “Anyone with the link” entirely

Time to Complete: ~30 minutes

Code Implementation

Validation & Testing

  1. Create test file and verify default sharing is Restricted
  2. Attempt to share externally - verify appropriate restrictions apply
  3. Audit existing files with external sharing
  4. Confirm allowed external sharing still functions
Code Pack: Terraform
hth-google-workspace-4.01-restrict-external-drive-sharing.tf View source on GitHub ↗
# Restrict external sharing of Google Drive files.  The googleworkspace
# provider does not directly manage Drive sharing settings (those are
# configured in Admin Console > Apps > Drive and Docs > Sharing settings).
#
# This control creates the organizational infrastructure to support
# sharing restrictions:
#
# 1. An OU for teams that need external collaboration (override at OU level)
# 2. Groups for managing allowed external domains
# 3. Audit tracking for files shared externally

# OU for teams that require external Drive sharing (e.g., Sales, Partnerships)
# These teams get slightly relaxed sharing settings while the rest of the
# organization defaults to internal-only.
resource "googleworkspace_org_unit" "external_sharing_allowed" {
  name                 = "External Sharing Allowed"
  description          = "HTH 4.1 -- Users in this OU may share Drive files with approved external domains"
  parent_org_unit_path = var.target_org_unit_path
}

# OU for highly sensitive teams with no external sharing whatsoever
resource "googleworkspace_org_unit" "no_external_sharing" {
  count = var.profile_level >= 2 ? 1 : 0

  name                 = "No External Sharing"
  description          = "HTH 4.1 L2 -- Users in this OU cannot share Drive files externally under any circumstances"
  parent_org_unit_path = var.target_org_unit_path
}

# Group for tracking external sharing exceptions and approvals
resource "googleworkspace_group" "external_sharing_approvers" {
  email       = "external-sharing-approvers@${var.primary_domain}"
  name        = "External Sharing Approvers"
  description = "HTH 4.1 -- Members can approve external Drive sharing requests"
}

# Group for collecting external sharing audit notifications
resource "googleworkspace_group" "external_sharing_audit" {
  email       = "external-sharing-audit@${var.primary_domain}"
  name        = "External Sharing Audit"
  description = "HTH 4.1 -- Receives notifications about external file sharing activity"
}
Code Pack: CLI Script
hth-google-workspace-4.01-audit-external-sharing.sh View source on GitHub ↗
# Audit files shared externally
gam all users print filelist query "visibility='anyoneWithLink' or visibility='anyoneCanFind'"

# Find files shared with specific external domains
gam all users print filelist query "sharedWithExternalUsers"

# Generate sharing report
gam report drive user all parameters doc_type,visibility,shared_with_user_accounts

4.2 Enable Data Loss Prevention (DLP)

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 3.1, 3.2
NIST 800-53 SC-8, SC-28

Description

Configure Google Workspace DLP rules to detect and prevent sharing of sensitive information like credit cards, SSNs, and confidential documents.

Prerequisites

  • Google Workspace Enterprise Standard or Plus
  • Defined sensitive data types for your organization

ClickOps Implementation

Step 1: Access DLP Settings

  1. Navigate to: Admin ConsoleSecurityAccess and data controlData protection
  2. Click Manage Rules

Step 2: Create DLP Rule

  1. Click Create rule
  2. Configure:
    • Name: Block sharing of PII
    • Scope: Entire organization or specific OUs
    • Apps: Drive, Chat
    • Conditions: Content matches predefined detectors (SSN, Credit Card, etc.)
    • Actions: Block external sharing, warn user, alert admin
  3. Save and enable rule

Code Implementation

Code Pack: Terraform
hth-google-workspace-4.02-enable-dlp.tf View source on GitHub ↗
# Google Workspace DLP uses the Cloud DLP API to detect sensitive data
# in Drive, Chat, and other Workspace services.  DLP requires Google
# Workspace Enterprise Standard or Plus.
#
# This creates a Cloud DLP inspect template with common PII detectors
# and a job trigger for scheduled scanning.  The actual Workspace DLP
# rules (block sharing, warn user) must be configured in:
#   Admin Console > Security > Data protection > Manage Rules

# DLP inspect template with common sensitive data detectors
resource "google_data_loss_prevention_inspect_template" "workspace_pii" {
  count = var.profile_level >= 2 && var.gcp_project_id != "" ? 1 : 0

  parent       = "projects/${var.gcp_project_id}"
  display_name = "HTH Workspace PII Template"
  description  = "HTH 4.2 -- Detects PII (SSN, credit cards, email addresses) in Workspace content"

  inspect_config {
    info_types {
      name = "US_SOCIAL_SECURITY_NUMBER"
    }
    info_types {
      name = "CREDIT_CARD_NUMBER"
    }
    info_types {
      name = "EMAIL_ADDRESS"
    }
    info_types {
      name = "PHONE_NUMBER"
    }
    info_types {
      name = "US_PASSPORT"
    }
    info_types {
      name = "US_DRIVERS_LICENSE_NUMBER"
    }

    min_likelihood = "LIKELY"

    limits {
      max_findings_per_request = 100
    }
  }
}

# L3: Extended DLP template with financial and healthcare data types
resource "google_data_loss_prevention_inspect_template" "workspace_regulated" {
  count = var.profile_level >= 3 && var.gcp_project_id != "" ? 1 : 0

  parent       = "projects/${var.gcp_project_id}"
  display_name = "HTH Workspace Regulated Data Template"
  description  = "HTH 4.2 L3 -- Detects regulated data (HIPAA, PCI) in Workspace content"

  inspect_config {
    info_types {
      name = "US_SOCIAL_SECURITY_NUMBER"
    }
    info_types {
      name = "CREDIT_CARD_NUMBER"
    }
    info_types {
      name = "CREDIT_CARD_TRACK_NUMBER"
    }
    info_types {
      name = "US_BANK_ROUTING_MICR"
    }
    info_types {
      name = "US_DEA_NUMBER"
    }
    info_types {
      name = "US_HEALTHCARE_NPI"
    }
    info_types {
      name = "IBAN_CODE"
    }
    info_types {
      name = "SWIFT_CODE"
    }
    info_types {
      name = "US_INDIVIDUAL_TAXPAYER_IDENTIFICATION_NUMBER"
    }

    min_likelihood = "POSSIBLE"

    limits {
      max_findings_per_request = 500
    }
  }
}

# Group for DLP incident notifications
resource "googleworkspace_group" "dlp_incidents" {
  count = var.profile_level >= 2 ? 1 : 0

  email       = "dlp-incidents@${var.primary_domain}"
  name        = "DLP Incidents"
  description = "HTH 4.2 -- Receives notifications when DLP rules are triggered"
}

5. Monitoring & Detection

5.1 Enable Audit Logging and Investigation Tool

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 8.2
NIST 800-53 AU-2, AU-3, AU-6
CIS Google Workspace 5.1

Description

Enable and configure audit logging across all Google Workspace services. Use the Security Investigation Tool for threat detection and incident response.

Rationale

Why This Matters:

  • Audit logs are essential for incident investigation
  • Provides visibility into admin actions, file access, and sign-in events
  • Required for compliance with most security frameworks

ClickOps Implementation

Step 1: Verify Audit Logging

  1. Navigate to: Admin ConsoleReportingAudit and investigation
  2. Verify logs are being captured for:
    • Admin activities
    • Login activities
    • Drive activities
    • Token activities
    • Rules activities

Step 2: Configure Audit Log Exports

  1. Navigate to: ReportingAudit and investigationExport to BigQuery
  2. Enable export to BigQuery for long-term retention
  3. Configure retention period

Step 3: Create Alert Rules

  1. Navigate to: SecurityAlert centerConfigure alerts
  2. Enable critical alerts:
    • Suspicious login
    • Government-backed attack
    • Device compromised
    • Super Admin added

Time to Complete: ~30 minutes

Key Events to Monitor

Event Log Source Detection Use Case
CHANGE_PASSWORD Admin Unauthorized password resets
GRANT_ADMIN_ROLE Admin Privilege escalation
CREATE_APPLICATION_SETTING Admin OAuth app approval
LOGIN_FAILURE Login Brute force attempts
SUSPICIOUS_LOGIN Login Account compromise
DOWNLOAD Drive Data exfiltration

Code Implementation

Code Pack: Terraform
hth-google-workspace-5.01-enable-audit-logging.tf View source on GitHub ↗
# Google Workspace audit logs are enabled by default.  This control
# ensures long-term retention via BigQuery export, creates alert
# notification groups, and sets up the GCP infrastructure for log
# analysis.

# BigQuery dataset for long-term audit log retention
resource "google_bigquery_dataset" "audit_logs" {
  count = var.gcp_project_id != "" ? 1 : 0

  dataset_id    = var.bigquery_dataset_id
  project       = var.gcp_project_id
  friendly_name = "Google Workspace Audit Logs"
  description   = "HTH 5.1 -- Long-term retention of Google Workspace audit logs"
  location      = "US"

  default_table_expiration_ms = var.log_retention_days * 24 * 60 * 60 * 1000

  labels = {
    purpose    = "security-audit"
    managed_by = "terraform"
    hth        = "5-01"
  }
}

# IAM binding to allow Workspace to write logs to BigQuery.
# The Workspace service account must have BigQuery Data Editor access.
resource "google_bigquery_dataset_iam_member" "workspace_writer" {
  count = var.gcp_project_id != "" ? 1 : 0

  dataset_id = google_bigquery_dataset.audit_logs[0].dataset_id
  project    = var.gcp_project_id
  role       = "roles/bigquery.dataEditor"
  member     = "serviceAccount:${var.service_account_email}"
}

# Group for security alert notifications
resource "googleworkspace_group" "security_alerts" {
  email       = "security-alerts@${var.primary_domain}"
  name        = "Security Alerts"
  description = "HTH 5.1 -- Receives Google Workspace security alert notifications (suspicious login, gov attack, device compromise)"
}

# Group for admin audit notifications
resource "googleworkspace_group" "admin_audit" {
  email       = "admin-audit@${var.primary_domain}"
  name        = "Admin Audit Notifications"
  description = "HTH 5.1 -- Receives notifications for admin actions (role changes, policy modifications)"
}

# L2: Create a dedicated service account for log analysis with read-only access
resource "google_bigquery_dataset_iam_member" "analyst_reader" {
  count = var.profile_level >= 2 && var.gcp_project_id != "" ? 1 : 0

  dataset_id = google_bigquery_dataset.audit_logs[0].dataset_id
  project    = var.gcp_project_id
  role       = "roles/bigquery.dataViewer"
  member     = "group:security-alerts@${var.primary_domain}"
}

# L2: BigQuery view for failed login attempts (pre-built detection query)
resource "google_bigquery_table" "failed_logins" {
  count = var.profile_level >= 2 && var.gcp_project_id != "" ? 1 : 0

  dataset_id = google_bigquery_dataset.audit_logs[0].dataset_id
  project    = var.gcp_project_id
  table_id   = "vw_failed_logins"

  view {
    query          = <<-SQL
      SELECT
        actor.email,
        COUNT(*) as failed_attempts,
        ARRAY_AGG(DISTINCT ip_address IGNORE NULLS) as source_ips
      FROM `${var.gcp_project_id}.${var.bigquery_dataset_id}.login_logs`
      WHERE event_name = 'login_failure'
        AND _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
      GROUP BY actor.email
      HAVING failed_attempts > 10
      ORDER BY failed_attempts DESC
    SQL
    use_legacy_sql = false
  }

  labels = {
    purpose    = "security-detection"
    managed_by = "terraform"
    hth        = "5-01"
  }
}

# L2: BigQuery view for external file sharing activity
resource "google_bigquery_table" "external_sharing" {
  count = var.profile_level >= 2 && var.gcp_project_id != "" ? 1 : 0

  dataset_id = google_bigquery_dataset.audit_logs[0].dataset_id
  project    = var.gcp_project_id
  table_id   = "vw_external_sharing"

  view {
    query          = <<-SQL
      SELECT
        actor.email,
        doc_title,
        target_user,
        event_time
      FROM `${var.gcp_project_id}.${var.bigquery_dataset_id}.drive_logs`
      WHERE event_name = 'change_user_access'
        AND target_user NOT LIKE '%@${var.primary_domain}'
        AND _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24 HOUR)
      ORDER BY event_time DESC
    SQL
    use_legacy_sql = false
  }

  labels = {
    purpose    = "security-detection"
    managed_by = "terraform"
    hth        = "5-01"
  }
}
Code Pack: CLI Script
hth-google-workspace-5.01-generate-audit-reports.sh View source on GitHub ↗
# Generate login report
gam report login start -7d end today

# Generate admin audit report
gam report admin start -7d end today

# Export Drive audit events
gam report drive start -7d end today event download

# Find suspicious logins
gam report login filter "is_suspicious==True"
Code Pack: DB Query
hth-google-workspace-5.01-bigquery-detection.sql View source on GitHub ↗
-- Find failed login attempts by user
SELECT
  actor.email,
  COUNT(*) as failed_attempts
FROM `project.dataset.login_logs`
WHERE event_name = 'login_failure'
  AND _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
GROUP BY actor.email
HAVING failed_attempts > 10
ORDER BY failed_attempts DESC;
-- Find external file sharing
SELECT
  actor.email,
  doc_title,
  target_user
FROM `project.dataset.drive_logs`
WHERE event_name = 'change_user_access'
  AND target_user NOT LIKE '%@yourdomain.com'
  AND _PARTITIONTIME >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24 HOUR);

6. Third-Party Integration Security

6.1 Integration Risk Assessment Matrix

Risk Factor Low Medium High
Data Access Read-only, limited scope Read most data Write access, full API
OAuth Scopes Specific scopes Broad API access Full admin/Gmail access
Session Duration Short-lived tokens Refresh tokens Offline access
Vendor Security SOC 2 Type II + ISO SOC 2 Type I No certification

Obsidian Security

Data Access: Read (Gmail metadata, Drive metadata, audit logs) Recommended Controls:

  • ✅ Use dedicated service account
  • ✅ Grant minimum required OAuth scopes
  • ✅ Review access quarterly
  • ✅ Monitor API usage via Reports

Slack

Data Access: Medium (Google Calendar, Drive file links) Recommended Controls:

  • ✅ Approve specific scopes only
  • ✅ Limit to approved workspaces
  • ✅ Monitor for unusual activity

7. Compliance Quick Reference

SOC 2 Trust Services Criteria Mapping

Control ID Google Workspace Control Guide Section
CC6.1 MFA for all users 1.1
CC6.1 OAuth app controls 3.1
CC6.2 Super Admin restrictions 1.2
CC6.6 External sharing restrictions 4.1
CC7.2 Audit logging 5.1

NIST 800-53 Rev 5 Mapping

Control Google Workspace Control Guide Section
IA-2(1) MFA enforcement 1.1
AC-6(1) Least privilege admin 1.2
AC-3 OAuth app control 3.1
AU-2 Audit logging 5.1

CIS Google Workspace Foundations Benchmark Mapping

Recommendation Google Workspace Control Guide Section
1.1 Ensure 2SV is enforced 1.1
1.2 Limit Super Admin accounts 1.2
2.1 Control third-party apps 3.1
3.1 Restrict external sharing 4.1

Appendix A: Edition/Tier Compatibility

Control Business Starter Business Standard Business Plus Enterprise Standard Enterprise Plus
2-Step Verification
Security Keys enforcement
OAuth app whitelisting
Context-Aware Access
Data Loss Prevention
Security Investigation Tool
BigQuery export

Appendix B: References

Official Google Documentation:

API & Developer Tools:

Compliance Frameworks:

Security Incidents:

  • Google Workspace has not had a major platform-level breach. Notable ecosystem incidents include the Google Docs OAuth Phishing Attack (2017), where a fake “Google Docs” app tricked users into granting email access via OAuth consent.

Third-Party Security Guides:


Changelog

Date Version Maturity Changes Author
2025-02-05 0.1.0 draft Initial guide with authentication, OAuth, data security, and monitoring controls Claude Code (Opus 4.5)

Contributing

Found an issue or want to improve this guide?