google-workspace

v0.4.2 collector

Collects Google Workspace identity and security posture metrics

Install

epack install collector google-workspace

Adds to epack.yaml, resolves dependencies, downloads binary.

Usage

Run all configured collectors and build a pack:

epack collect

Runs all collectors in epack.yaml and outputs an evidence pack.

Configuration

Or add manually to epack.yaml:

collectors:
  google-workspace:
    source: https://github.com/locktivity/epack-collector-google-workspace

Then run epack install to lock and sync.

Google Workspace Collector Overview

The Google Workspace collector gathers security posture metrics from your Google Workspace tenant. It covers authentication strength, account hygiene, privileged access, password health, third-party app exposure, and positive-only Context-Aware Access deny evidence related to device state.

Output

The collector always emits a detailed artifact, and conditionally emits a normalized artifact when the usage report contains data:

  • artifacts/google-workspace.json — detailed Google Workspace posture metrics (always emitted)
  • artifacts/google-workspace.idp-posture.json — normalized evidencepack/idp-posture@v1 artifact for cross-provider comparison (omitted when the usage report is empty, e.g. for new tenants)

Google Workspace Artifact

{
  "schema_version": "1.0.0",
  "collected_at": "2026-04-08T12:00:00Z",
  "usage_report_date": "2026-04-07",
  "provider": "google-workspace",
  "org_domain": "example.com",
  "customer_id": "C123abc",
  "users": {
    "total": 120,
    "suspended": 10,
    "archived": 5,
    "locked_pct": 0.83,
    "inactive_pct": 4.76,
    "inactive_days": 90
  },
  "activity": {
    "active_7d_pct": 78.33,
    "active_30d_pct": 91.67
  },
  "authentication": {
    "2sv_enrolled_pct": 92.5,
    "2sv_enforced_pct": 88.33,
    "2sv_protected_pct": 90.0,
    "passkey_users_pct": 12.5,
    "security_keys_total": 35
  },
  "admins": {
    "privileged_users_count": 7,
    "super_admin_count": 3,
    "delegated_admin_count": 5,
    "privileged_users_2sv_enrolled_pct": 85.71,
    "privileged_users_2sv_enforced_pct": 100.0
  },
  "passwords": {
    "weak_password_pct": 4.17,
    "password_length_non_compliant_pct": 2.5,
    "policy": {
      "minimum_length": 8,
      "maximum_length": 100,
      "allowed_strength": "strong",
      "enforce_requirements_at_login": false,
      "allow_reuse": false,
      "expiration_days": 0,
      "distinct_policies": 2
    }
  },
  "apps": {
    "authorized_apps_count": 47
  },
  "device_access": {
    "lookback_days": 90,
    "context_aware_access_denied_events": 12,
    "device_state_denied_events": 4,
    "managed_device_requirement_evidenced": true,
    "access_context_manager": {
      "access_policy_name": "accessPolicies/123456789",
      "access_policy_parent": "organizations/987654321",
      "basic_access_levels_count": 6,
      "custom_access_levels_count": 1,
      "basic_device_policy_access_levels_count": 2,
      "basic_managed_device_access_levels_count": 1,
      "basic_device_policy_access_level_titles": ["Corp Device", "High Trust Device"]
    }
  }
}

Normalized IDP Posture Artifact

{
  "schema_version": "1.0.0",
  "collected_at": "2026-04-08T12:00:00Z",
  "provider": "google_workspace",
  "org_domain": "example.com",
  "user_security": {
    "mfa_coverage_pct": 90.0,
    "mfa_phishing_resistant_pct": 12.5,
    "inactive_pct": 4.76,
    "locked_out_pct": 0.83,
    "weak_password_pct": 4.17,
    "password_policy_noncompliant_pct": 2.5
  },
  "app_security": {
    "authorized_third_party_apps_count": 47
  },
  "privileged_access": {
    "privileged_users_count": 7,
    "super_admin_count": 3,
    "privileged_mfa_coverage_pct": 85.71,
    "standing_privileged_users_count": 7
  },
  "policy": {
    "mfa_required": false,
    "mfa_required_coverage_pct": 88.33,
    "legacy_auth_blocked": true,
    "minimum_password_length": 8,
    "password_strength_required": true,
    "password_policy_enforced_for_existing_users": false
  },
  "lifecycle": {
    "suspended_pct": 8.33,
    "archived_pct": 4.17
  },
  "device_access": {
    "managed_device_required": true
  }
}

The normalized artifact follows the evidencepack/idp-posture@v1 schema, matching the same shape used by the Okta and other IDP collectors.

policy.legacy_auth_blocked is emitted as true for Google Workspace because Google no longer supports less secure username/password-only app access for Workspace accounts.

Normalized field Google Workspace source Notes
mfa_coverage_pct 2sv_protected_pct Effective MFA coverage, not just enrollment
mfa_phishing_resistant_pct passkey_users_pct Passkey adoption as phishing-resistant proxy
weak_password_pct weak_password_pct Weak password coverage comes directly from the usage report
password_policy_noncompliant_pct password_length_non_compliant_pct Tracks users that fail the tenant password length policy
policy.minimum_password_length passwords.policy.minimum_length Shortest password accepted anywhere in the tenant
policy.password_strength_required passwords.policy.allowed_strength Derived: true when the tenant requires strong passwords everywhere
policy.password_policy_enforced_for_existing_users passwords.policy.enforce_requirements_at_login Whether the rules bind users who already have a password
app_security.authorized_third_party_apps_count authorized_apps_count OAuth-connected third-party application count
privileged_access.privileged_users_count privileged_users_count Counts unique active privileged users only
privileged_access.super_admin_count super_admin_count Excludes suspended and archived admins
privileged_access.privileged_mfa_coverage_pct privileged_users_2sv_enrolled_pct Percent of active privileged users with 2SV enrolled
privileged_access.standing_privileged_users_count privileged_users_count Google Workspace has standing admin roles in this collector model
policy.mfa_required 2sv_enforced_pct == 100 Only true when all users have 2SV enforced by policy
policy.mfa_required_coverage_pct 2sv_enforced_pct Preserves partial enforcement coverage instead of dropping the policy block
policy.legacy_auth_blocked Google Workspace platform behavior Google Workspace no longer supports less secure username/password apps for tenant access
lifecycle.suspended_pct suspended / total Uses the usage report's suspended user count
lifecycle.archived_pct archived / total Uses the usage report's archived user count
device_access.managed_device_required device_access.managed_device_requirement_evidenced Emitted only when Context-Aware Access deny events include a device-state parameter

app_security.sso_coverage_pct, app_security.provisioning_enabled_pct, and app_security.deprovisioning_enabled_pct are omitted because the Reports and Directory APIs do not expose per-app SSO or provisioning settings. policy.session_lifetime_max_min, policy.idle_timeout_max_min, policy.phishing_resistant_required_for_privileged, and device_access.managed_device_required_for_admins are also omitted because those tenant controls are not available through these APIs in a reliable tenant-wide form.

device_access.managed_device_required is positive-only evidence derived from Context-Aware Access audit logs. The collector sets it only when Google reports ACCESS_DENY_EVENT entries whose parameters include a device-state field. This is evidence that a device-state access level fired, not proof of complete policy coverage, and Google does not emit grant events for clean passes. Context-Aware Access monitor mode can also produce similar deny-style events, so the collector surfaces this as evidence with an explicit diagnostics caveat rather than as a full configuration truth.

When organization_id or access_policy is configured and the service account has roles/accesscontextmanager.policyReader, the detailed artifact also includes an access_context_manager summary under device_access. This summarizes basic access levels with devicePolicy conditions and counts any custom CEL access levels, but it still does not prove which Workspace apps those levels are attached to.

Metrics Reference

users

User population and account health.

Metric Why It Matters
total Tenant size. Total user accounts including suspended and archived.
suspended Disabled accounts. Users administratively suspended from the tenant.
archived Retained accounts. Users archived but not deleted, often for compliance retention.
locked_pct Potential attack indicator. Spikes in lockout rates may indicate brute force or credential stuffing attacks.
inactive_pct Orphan account risk. Inactive accounts (90+ days no login) are prime targets for attackers. They may belong to departed employees or unused service accounts.
inactive_days Inactivity threshold. The number of days used to classify a user as inactive (default: 90).

activity

Login activity rates across the tenant.

Metric Why It Matters
active_7d_pct Short-term engagement. Percentage of users who logged in within the last 7 days. Low values may indicate shadow IT or alternative access paths.
active_30d_pct Monthly engagement. Percentage of users active in the last 30 days. A large gap between this and 7-day activity may indicate periodic or seasonal users.

authentication

Two-step verification and phishing-resistant credential adoption.

Metric Why It Matters
2sv_enrolled_pct Account takeover protection. 2-step verification significantly reduces credential-based attacks. Low enrollment leaves accounts vulnerable to password spraying and phishing.
2sv_enforced_pct Policy enforcement. Users with 2SV enforced by admin policy, not just voluntarily enrolled. The gap between enrolled and enforced indicates reliance on user opt-in.
2sv_protected_pct Effective protection. Users actually protected by 2SV (enrolled, enforced, and no bypass). This is the strongest signal of real MFA coverage.
passkey_users_pct Passwordless adoption. Passkeys are phishing-resistant by design. Tracks progress toward eliminating password-based authentication.
security_keys_total Hardware key inventory. Total registered security keys (FIDO2/U2F). Useful for tracking hardware rollout across the organization.

admins

Privileged account exposure and enforcement.

Metric Why It Matters
privileged_users_count Unique privileged identities. Counts active users with any privileged role without double-counting users that hold multiple admin role types.
super_admin_count Blast radius. Super admins have unrestricted access. Fewer is better. Industry guidance recommends 2-4 for business continuity without excess risk.
delegated_admin_count Delegated access scope. Delegated admins have subset privileges. High counts may indicate over-delegation.
privileged_users_2sv_enrolled_pct Admin MFA coverage. Tracks whether privileged users have actually enrolled in 2SV, which is the closest Google Workspace signal to real privileged MFA coverage.
privileged_users_2sv_enforced_pct Admin MFA enforcement. The single most important metric for third-party risk. 100% means all active privileged users have 2SV enforced by policy.

passwords

Password hygiene across the tenant.

Metric Why It Matters
weak_password_pct Credential strength. Users with passwords classified as weak by Google. Indicates exposure to brute force and dictionary attacks.
password_length_non_compliant_pct Policy compliance. Users whose passwords don't meet the configured minimum length requirement. Non-zero values indicate policy enforcement gaps.
policy.minimum_length The requirement itself. The shortest password the tenant will accept. Without it, a zero non-compliance rate is ambiguous: it reads the same whether the minimum is 14 or Google's floor of 8.
policy.maximum_length Upper bound. Informational.
policy.allowed_strength Strength requirement. strong means Google rejects passwords its strength algorithm rates weak. Google Workspace has no character-class complexity setting; this is the equivalent control.
policy.enforce_requirements_at_login Does the policy bind existing users? False means a password that predates the policy survives until its owner chooses to change it. This is what makes the non-compliance percentage interpretable: with enforcement off, a zero rate is voluntary compliance rather than a forced migration.
policy.allow_reuse Reuse restriction. True means a previous password can be set again.
policy.expiration_days Rotation. 0 means passwords never expire, which is the weakest setting rather than the strongest.
policy.distinct_policies Uniformity. Greater than 1 means org units or groups have different policies and every value above describes the weakest one in force.

The policy values describe the weakest policy anywhere in the tenant, so a
reviewer can rely on them holding everywhere. The whole policy object is
omitted when it could not be read: absence never means permissive.

Google does not apply these requirements to passwords set through the Directory
API, the bulk upload tool, sync tools, or an administrator reset. That is why
the outcome percentages stay alongside the policy rather than being replaced by
it: the percentages observe what the policy bypasses.

apps

Third-party application exposure.

Metric Why It Matters
authorized_apps_count OAuth exposure surface. Number of third-party apps authorized to access tenant data. High counts increase data exfiltration risk and expand the supply chain attack surface.

device_access

Context-Aware Access deny evidence.

Metric Why It Matters
lookback_days Evidence window. Number of days of audit history searched for device-state-based denials.
context_aware_access_denied_events Control activity. Total Context-Aware Access deny events seen in the audit window.
device_state_denied_events Managed-device evidence. Denials that specifically included a device-state parameter, indicating device posture was part of the access decision.
managed_device_requirement_evidenced Positive-only signal. true means Google audit logs show device-state access levels firing somewhere in the tenant; it is not proof of full policy coverage, and monitor-mode events can look similar.
access_context_manager.* Config enrichment. Optional Google Cloud access-level summary that helps you see whether the org has basic device-policy access levels configured, even though Workspace-side app assignment is still API-thin.

Use Cases

  • Third-Party Risk Assessment: Share aggregated posture metrics under NDA without exposing user-level details
  • Security Baseline Monitoring: Track 2SV enrollment, admin MFA enforcement, and password hygiene over time
  • Compliance Evidence: Demonstrate MFA coverage and account lifecycle controls for SOC 2, ISO 27001, and similar frameworks
  • Privileged Access Review: Monitor super admin counts and admin 2SV enforcement as a leading indicator of identity risk

Setting up the Google Workspace collector

Follow these steps once. Steps 1 to 3 and 5 to 6 are the same whichever
authentication mode you use; step 4 is where they differ.

Step 1: Create a Cloud project

  1. Open the Google Cloud console.
  2. Create or select a project for the collector.
  3. Go to APIs & Services > Enabled APIs and enable the APIs below.
API Enable it for
Admin SDK API Every run
Cloud Identity API Every run (password policy; SAML profiles at audit and above)
IAM Service Account Credentials API auth_mode: oidc only
Groups Settings API audit and internal
Google Vault API audit and internal (also needs a Vault license)
Access Context Manager API Optional device_access enrichment

APIs are separate from OAuth scopes. If an API is off, its surface fails with a
SERVICE_DISABLED diagnostic even when the scope is granted, and the rest of
the run continues.

Step 2: Create a service account

  1. Go to IAM & Admin > Service Accounts.
  2. Click Create Service Account.
  3. Name it, for example epack-collector.
  4. Click Create and Continue, then Done. It needs no project-level roles.

Step 3: Enable domain-wide delegation

  1. Open the service account you just created.
  2. On the Details tab, under Advanced settings, click Enable Domain-wide Delegation.
  3. Copy the Client ID. Step 5 needs it.

Step 4: Set up authentication

Choose one. oidc creates no key and is preferred on CI.

Option A: auth_mode oidc

Everything here is in the same Cloud project as the service account.

  1. Create a workload identity pool.
  2. Create a provider in that pool trusting your CI provider's OIDC issuer.
  3. Add an attribute condition restricting the provider to your repository or organization. Without one, any repository on that issuer can assume the identity.
  4. Grant the workload identity principal roles/iam.workloadIdentityUser on the service account. This lets the runner act as it.
  5. Grant the service account roles/iam.serviceAccountTokenCreator on itself. This lets it sign delegation assertions with the Google-managed key.
  6. In epack.yaml, set auth_mode: oidc, workload_identity_provider, and service_account, and list ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN under secrets:.
  7. In the workflow, grant the id-token: write permission.

Step 5 is easy to miss. The service account holds a role on itself, which looks
odd but is what allows signing without a downloaded key.

The collector builds the exchange and impersonation endpoints from the two
config keys, so no credential file is involved and no auth step is needed in the
workflow.

Option B: auth_mode service_account_key

Skip this if you followed Option A. Some organizations block key creation with
the iam.disableServiceAccountKeyCreation policy.

  1. Open the service account's Keys tab.
  2. Click Add Key > Create new key > JSON.
  3. Store the downloaded file securely and pass its contents as GOOGLE_SERVICE_ACCOUNT_JSON.

This key grants access to your tenant. Treat it as a credential.

Step 5: Authorize scopes in Google Workspace

  1. Open the Google Workspace admin console.
  2. Go to Security > Access and data control > API controls > Domain-wide delegation.
  3. Click Add new.
  4. Enter the Client ID from step 3.
  5. Add the scopes for the levels you plan to collect, from the table below.
  6. Click Authorize.
Surface Scope Needed at
Customer + Users admin.directory.user.readonly, admin.directory.customer.readonly trust
Activity / usage admin.reports.usage.readonly trust
Context-Aware Access (device_access) admin.reports.audit.readonly trust
Password policy cloud-identity.policies.readonly trust
Audit logs (admin, login, token, drive sharing) admin.reports.audit.readonly audit / internal
Admin roles admin.directory.rolemanagement.readonly audit / internal
Groups admin.directory.group.readonly, admin.directory.group.member.readonly, apps.groups.settings audit / internal
Org units admin.directory.orgunit.readonly audit / internal
Endpoint (devices) admin.directory.device.mobile.readonly, admin.directory.device.chromeos.readonly audit / internal
Domain settings admin.directory.domain.readonly audit / internal
SSO (SAML profiles) cloud-identity.inboundsso.readonly audit / internal
Vault (eDiscovery) ediscovery.readonly audit / internal (requires a Vault license)

All scopes as one comma-separated list, for pasting into the admin console:

https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.customer.readonly,https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly,https://www.googleapis.com/auth/admin.directory.group.readonly,https://www.googleapis.com/auth/admin.directory.group.member.readonly,https://www.googleapis.com/auth/admin.directory.orgunit.readonly,https://www.googleapis.com/auth/admin.directory.device.mobile.readonly,https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/admin.reports.usage.readonly,https://www.googleapis.com/auth/admin.reports.audit.readonly,https://www.googleapis.com/auth/apps.groups.settings,https://www.googleapis.com/auth/cloud-identity.inboundsso.readonly,https://www.googleapis.com/auth/cloud-identity.policies.readonly,https://www.googleapis.com/auth/ediscovery.readonly

Grants are not retroactive. If you add a scope later, re-grant it here.

Step 6: Choose the admin user to impersonate

Set admin_email to a Super Admin account; several of the admin API reads
require one. The read-only scopes from step 5 still limit what the collector
can read. A common setup is a dedicated epack-collector@<domain> user.

Optional: Access Context Manager enrichment

Adds access-level config to the detailed artifact alongside Context-Aware Access
deny evidence.

  1. Grant the service account roles/accesscontextmanager.policyReader on the Cloud organization.
  2. Set one of:
    • organization_id, to discover the policy under organizations/{id}.
    • access_policy, an explicit policy resource such as accessPolicies/123456789 or its numeric ID. Takes precedence.

The normalized artifact stays conservative either way, because Workspace-side
app assignment and monitor-mode details are not fully exposed by API.

Config options

Option Required Description
admin_email Yes Workspace admin account to impersonate
auth_mode No oidc, or service_account_key when omitted
workload_identity_provider With oidc Full provider resource path
service_account With oidc Account to impersonate and sign as
customer No Google customer key. Defaults to my_customer
organization_id No Cloud organization ID for device_access enrichment
access_policy No Explicit Access Context Manager policy. Takes precedence over organization_id

Environment variables

Variable Description
GOOGLE_SERVICE_ACCOUNT_JSON Key file contents, not a path. Required for service_account_key, unused for oidc
ACTIONS_ID_TOKEN_REQUEST_URL Set by GitHub Actions when the workflow grants id-token: write. Required for oidc
ACTIONS_ID_TOKEN_REQUEST_TOKEN Set alongside the URL. Authorizes fetching one identity token per run. Required for oidc

Troubleshooting

A missing scope, API, or role never fails the run, except for the tenant
record: it is read first, requires a Super Admin, and stops the run when
denied (step 6). Any other affected surface is omitted and a diagnostic says
which of the three is missing, because each is fixed in a different console.

The run fails to start

Message Fix
authentication required: provide GOOGLE_SERVICE_ACCOUNT_JSON Pass the key contents, or set auth_mode: oidc
invalid auth_mode Use oidc or service_account_key
workload_identity_provider is not set auth_mode: oidc needs it and service_account
the runner exposes no OIDC identity Add id-token: write to the workflow, and list the two request variables under secrets:
creating JWT config GOOGLE_SERVICE_ACCOUNT_JSON is not valid JSON. Copy-paste often truncates it

Authentication fails on the first API call

With auth_mode: oidc, the exchange and the signing are deferred until
something is collected, so setup mistakes appear here rather than at startup.

Message mentions Fix
roles/iam.serviceAccountTokenCreator Grant that role to the service account on itself (step 4, item 5)
iamcredentials.googleapis.com Enable the IAM Service Account Credentials API
the workload identity exchange was rejected Check the pool, the provider's attribute condition, and roles/iam.workloadIdentityUser
401 Unauthorized Confirm admin_email is a real admin, delegation is enabled, and the Client ID matches
admin_email must be a Super Admin Impersonate a Super Admin (step 6); narrower admin roles, including custom ones, cannot read the tenant record
admin.directory.customer.readonly scope is not granted Re-check the scope list from step 5 in the admin console

A surface is missing from the artifact

Check the diagnostics block. It names which of the three grants is missing.

Diagnostic Fix
scope denied Add that scope in the admin console and re-grant
SERVICE_DISABLED Enable that API in the Cloud project
admin role Give the impersonated user a role that can read the surface
feature requires a license The tenant's edition does not include it, for example Vault

The password policy is missing

passwords.policy is omitted rather than zeroed when it cannot be read, so an
absent policy never reads as a permissive one. The diagnostics distinguish a
missing scope, a disabled API, an insufficient role, an edition without the
Policy API, and a tenant that exposes no policy.

Usage report data is empty

Usage reports cover the previous day, and very new tenants may have none yet.
The usage_report_date field shows which day the artifact covers.

Examples

Basic Usage

stream: myorg/google-workspace-posture

collectors:
  google-workspace:
    source: locktivity/epack-collector-google-workspace@^0.2
    config:
      admin_email: admin@example.com
    secrets:
      - GOOGLE_SERVICE_ACCOUNT_JSON

Then run:

export GOOGLE_SERVICE_ACCOUNT_JSON="$(cat /path/to/service-account.json)"
epack collect

See Configuration for service account setup instructions.

Explicit Customer Key

If your service account has access to a specific Google Workspace tenant, set the customer key explicitly:

collectors:
  google-workspace:
    source: locktivity/epack-collector-google-workspace@^0.2
    config:
      customer: C0123abc
      organization_id: "987654321"
      admin_email: admin@example.com
    secrets:
      - GOOGLE_SERVICE_ACCOUNT_JSON

Sample Output

The collector always emits the detailed artifact. The normalized artifact is included when the usage report contains data (omitted for new tenants or delayed reports).

artifacts/google-workspace.json

{
  "schema_version": "1.0.0",
  "collected_at": "2026-04-08T12:00:00Z",
  "usage_report_date": "2026-04-07",
  "provider": "google-workspace",
  "org_domain": "example.com",
  "customer_id": "C123abc",
  "users": {
    "total": 120,
    "suspended": 10,
    "archived": 5,
    "locked_pct": 0.83,
    "inactive_pct": 4.76,
    "inactive_days": 90
  },
  "activity": {
    "active_7d_pct": 78.33,
    "active_30d_pct": 91.67
  },
  "authentication": {
    "2sv_enrolled_pct": 92.5,
    "2sv_enforced_pct": 88.33,
    "2sv_protected_pct": 90.0,
    "passkey_users_pct": 12.5,
    "security_keys_total": 35
  },
  "admins": {
    "privileged_users_count": 7,
    "super_admin_count": 3,
    "delegated_admin_count": 5,
    "privileged_users_2sv_enrolled_pct": 85.71,
    "privileged_users_2sv_enforced_pct": 100.0
  },
  "passwords": {
    "weak_password_pct": 4.17,
    "password_length_non_compliant_pct": 2.5,
    "policy": {
      "minimum_length": 8,
      "maximum_length": 100,
      "allowed_strength": "strong",
      "enforce_requirements_at_login": false,
      "allow_reuse": false,
      "expiration_days": 0,
      "distinct_policies": 2
    }
  },
  "apps": {
    "authorized_apps_count": 47
  },
  "device_access": {
    "lookback_days": 90,
    "context_aware_access_denied_events": 12,
    "device_state_denied_events": 4,
    "managed_device_requirement_evidenced": true,
    "access_context_manager": {
      "access_policy_name": "accessPolicies/123456789",
      "access_policy_parent": "organizations/987654321",
      "basic_access_levels_count": 6,
      "custom_access_levels_count": 1,
      "basic_device_policy_access_levels_count": 2,
      "basic_managed_device_access_levels_count": 1,
      "basic_device_policy_access_level_titles": ["Corp Device", "High Trust Device"]
    }
  }
}

artifacts/google-workspace.idp-posture.json

{
  "schema_version": "1.0.0",
  "collected_at": "2026-04-08T12:00:00Z",
  "provider": "google_workspace",
  "org_domain": "example.com",
  "user_security": {
    "mfa_coverage_pct": 90.0,
    "mfa_phishing_resistant_pct": 12.5,
    "inactive_pct": 4.76,
    "locked_out_pct": 0.83,
    "weak_password_pct": 4.17,
    "password_policy_noncompliant_pct": 2.5
  },
  "app_security": {
    "authorized_third_party_apps_count": 47
  },
  "privileged_access": {
    "privileged_users_count": 7,
    "super_admin_count": 3,
    "privileged_mfa_coverage_pct": 85.71,
    "standing_privileged_users_count": 7
  },
  "policy": {
    "mfa_required": false,
    "mfa_required_coverage_pct": 88.33,
    "legacy_auth_blocked": true,
    "minimum_password_length": 8,
    "password_strength_required": true,
    "password_policy_enforced_for_existing_users": false
  },
  "lifecycle": {
    "suspended_pct": 8.33,
    "archived_pct": 4.17
  },
  "device_access": {
    "managed_device_required": true
  }
}

All coverage values are percentages (0-100). See Overview for detailed metric descriptions.

CI/CD Integration

GitHub Actions

name: Collect Google Workspace Posture

on:
  schedule:
    - cron: "0 6 * * *"
  workflow_dispatch:

jobs:
  collect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install epack
        run: |
          curl -sSL https://install.epack.dev | bash

      - name: Collect evidence
        run: epack collect --frozen
        env:
          GOOGLE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }}

Store the service account JSON as a repository secret named GOOGLE_SERVICE_ACCOUNT_JSON.

Multiple Google Workspace Tenants

If a single service account has domain-wide delegation across tenants, use the customer key to target each one in its own epack.yaml:

# epack-prod.yaml
collectors:
  google-workspace:
    source: locktivity/epack-collector-google-workspace@^0.2
    config:
      customer: C0abc123
      admin_email: admin@company.com
    secrets:
      - GOOGLE_SERVICE_ACCOUNT_JSON
# epack-subsidiary.yaml
collectors:
  google-workspace:
    source: locktivity/epack-collector-google-workspace@^0.2
    config:
      customer: C0def456
      admin_email: admin@subsidiary.com
    secrets:
      - GOOGLE_SERVICE_ACCOUNT_JSON
export GOOGLE_SERVICE_ACCOUNT_JSON="$(cat service-account.json)"
epack collect -c epack-prod.yaml
epack collect -c epack-subsidiary.yaml

If each tenant requires its own service account, run separate invocations with different credentials:

GOOGLE_SERVICE_ACCOUNT_JSON="$(cat prod-sa.json)" epack collect -c epack-prod.yaml
GOOGLE_SERVICE_ACCOUNT_JSON="$(cat subsidiary-sa.json)" epack collect -c epack-subsidiary.yaml
v0.4.2 Latest
2026-08-25

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.4.1...v0.4.2

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.4.1
2026-08-20

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.4.0...v0.4.1

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.4.0
2026-08-18

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.3.1...v0.4.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.3.1
2026-07-16

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.3.0...v0.3.1

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.3.0
2026-07-16

## What's Changed * Add audience levels by @mnipper in https://github.com/locktivity/epack-collector-google-workspace/pull/1 * Move authorized apps/OAuth tokens to internal, activity to audit+; fix dep vulns by @fhodnett in https://github.com/locktivity/epack-collector-google-workspace/pull/2 ## New Contributors * @mnipper made their first contribution in https://github.com/locktivity/epack-collector-google-workspace/pull/1 * @fhodnett made their first contribution in https://github.com/locktivity/epack-collector-google-workspace/pull/2 **Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.2.0...v0.3.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.2.0
2026-05-20

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.2...v0.2.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.2
2026-04-22

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.1...v0.1.2

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.1
2026-04-22

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.0...v0.1.1

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64
v0.1.0
2026-04-21

**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/commits/v0.1.0

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64

Details

Publisher
locktivity
Latest
v0.4.2
Protocol
v1

Platforms

darwin/amd64 darwin/arm64 linux/amd64 linux/arm64

Links