# 5 Account inventory (incl. shared/service accounts)

> v0.0.3 · role: Assure · [policy: #10 · #28](https://docs.google.com/spreadsheets/d/1nOztaPd1Y7eNeRSR_hdovYy-ncpx-bAx/edit?usp=sharing&ouid=115159875779023172526&rtpof=true&sd=true)

A dated register of every account — human, shared and service — each with a named owner. It is built by exporting users, groups and group memberships with GAM (the command-line Workspace admin tool), then reconciling that against the human register and cross-checking the identities that never appear as ordinary users: GCP service accounts and domain-wide delegation clients. The point of the register is that it makes an unowned account a finding rather than a curiosity, so an orphaned or attacker-created identity has nowhere to hide.

## Caveats

- The inventory is only as good as its 'unowned = suspicious' rule — an account with a plausible name and no owner is exactly what an attacker leaves behind.
- lastLoginTime is blank for accounts that have never signed in and for some SSO paths — do not read blank as dormant without checking the audit log.
- Suspended accounts still hold data and can be re-enabled by any super admin — count them in, do not filter them out.

## Setup steps

1. Export the authoritative user list with GAM (the command-line Google Workspace admin tool) and store it as the dated inventory snapshot.

   ```
   gam print users fields primaryEmail,name,suspended,isAdmin,isDelegatedAdmin,lastLoginTime,creationTime,orgUnitPath > users-$(date +%F).csv
   ```

   docs: [Download a list of users](https://knowledge.workspace.google.com/admin/users/advanced/download-a-list-of-users) · [REST Resource: users | Admin SDK Directory API](https://developers.google.com/workspace/admin/directory/reference/rest/v1/users)

2. Export groups and their membership, so shared mailboxes and service identities are captured too.

   ```
   gam print groups fields email,name,description,adminCreated > groups-$(date +%F).csv  &&  gam print group-members > group-members-$(date +%F).csv
   ```

3. Enumerate non-human identities that never appear as ordinary users: service accounts and domain-wide delegation clients. — `Security › Access and data control › API controls › Manage Domain Wide Delegation`

   Cross-check GCP service accounts and Security > Access and data control > API controls > Manage Domain Wide Delegation against the register

   docs: [Control API access with domain-wide delegation](https://knowledge.workspace.google.com/admin/apps/control-api-access-with-domain-wide-delegation) · [List and edit service accounts](https://docs.cloud.google.com/iam/docs/service-accounts-list-edit)

4. Reconcile the export against the human register (HR list + owned shared accounts) and open the console on any row that has no owner. — `Directory › Users`

   ```
   Diff = zero unexplained accounts; every account has a named owner and a purpose
   ```

5. Flag groups with external members or no owner for the exposure lockdown control ([№32](groups-exposure-lockdown.md)). — `Directory › Groups`

   Owner set; external members reviewed

## Ongoing maintenance

- **[automatable: script]** Monthly: re-export users/groups/delegation clients and diff against the register.
- **[requires a human]** Monthly: triage every unowned or unexplained account the diff surfaces.

## How to verify

1. Check the newest inventory snapshot is no older than the cycle, then re-run the export and diff — an inventory is only as good as its date.

   ```
   gam print users fields primaryEmail,suspended,lastLoginTime > users-check.csv && diff <(sort users-check.csv) <(sort users-<last-date>.csv)
   ```

## Settings screens

- Directory > Users
  - console: https://admin.google.com/ac/users
  - screenshot: ../screenshots/admin.google.com/ac/users.png
- Directory > Groups
  - console: https://admin.google.com/ac/groups
  - screenshot: ../screenshots/admin.google.com/ac/groups.png
- Security > Access and data control > API controls > Manage Domain Wide Delegation
  - console: https://admin.google.com/ac/owl/domainwidedelegation
  - screenshot: ../screenshots/admin.google.com/ac/owl/domainwidedelegation.png
