Collects Google Workspace identity and security posture metrics
epack install collector google-workspace
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
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.
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.
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){
"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"]
}
}
}
{
"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.
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). |
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. |
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. |
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. |
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.
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. |
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. |
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.
| 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.
epack-collector.Choose one. oidc creates no key and is preferred on CI.
Everything here is in the same Cloud project as the service account.
roles/iam.workloadIdentityUser on the
service account. This lets the runner act as it.roles/iam.serviceAccountTokenCreator on itself.
This lets it sign delegation assertions with the Google-managed key.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:.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.
Skip this if you followed Option A. Some organizations block key creation with
the iam.disableServiceAccountKeyCreation policy.
GOOGLE_SERVICE_ACCOUNT_JSON.This key grants access to your tenant. Treat it as a credential.
| 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.
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.
Adds access-level config to the detailed artifact alongside Context-Aware Access
deny evidence.
roles/accesscontextmanager.policyReader on the
Cloud organization.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.
| 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 |
| 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 |
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.
| 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 |
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 |
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 |
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 reports cover the previous day, and very new tenants may have none yet.
The usage_report_date field shows which day the artifact covers.
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.
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
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.
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.
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
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.4.1...v0.4.2
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.4.0...v0.4.1
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.3.1...v0.4.0
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.3.0...v0.3.1
## 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
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.2...v0.2.0
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.1...v0.1.2
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/compare/v0.1.0...v0.1.1
**Full Changelog**: https://github.com/locktivity/epack-collector-google-workspace/commits/v0.1.0