Skip to content
5 changes: 3 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ steampipe plugin install googleworkspace

| Item | Description |
| :---------- | :-----------|
| APIs | 1. Go to the [Google API Console](https://console.cloud.google.com/apis/dashboard). <br/> 2. Select the project that contains your credentials. <br/> 3. Click `Enable APIs and Services`. <br/> 4. Enable: `Google Calendar API`, `Google Drive API`, `Gmail API`, `Google People API`.
| Credentials | 1. To use **domain-wide delegation**, generate your [service account and credentials](https://developers.google.com/admin-sdk/directory/v1/guides/delegation#create_the_service_account_and_credentials) and [delegate domain-wide authority to your service account](https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account). Enter the following OAuth 2.0 scopes for the services that the service account can access:<br />`https://www.googleapis.com/auth/calendar.readonly`,<br />`https://www.googleapis.com/auth/contacts.readonly`,<br />`https://www.googleapis.com/auth/contacts.other.readonly`,<br />`https://www.googleapis.com/auth/directory.readonly`,<br />`https://www.googleapis.com/auth/drive.readonly`,<br />`https://www.googleapis.com/auth/gmail.readonly`<br />2. To use **OAuth client**, configure your [credentials](#authenticate-using-oauth-client). |
| APIs | 1. Go to the [Google API Console](https://console.cloud.google.com/apis/dashboard). <br/> 2. Select the project that contains your credentials. <br/> 3. Click `Enable APIs and Services`. <br/> 4. Enable: `Google Calendar API`, `Google Drive API`, `Gmail API`, `Google People API`, `Google Admin SDK API`.
| Credentials | 1. To use **domain-wide delegation**, generate your [service account and credentials](https://developers.google.com/admin-sdk/directory/v1/guides/delegation#create_the_service_account_and_credentials) and [delegate domain-wide authority to your service account](https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account). Enter the following OAuth 2.0 scopes for the services that the service account can access:<br />`https://www.googleapis.com/auth/admin.reports.audit.readonly`<br />`https://www.googleapis.com/auth/calendar.readonly`,<br />`https://www.googleapis.com/auth/contacts.readonly`,<br />`https://www.googleapis.com/auth/contacts.other.readonly`,<br />`https://www.googleapis.com/auth/directory.readonly`,<br />`https://www.googleapis.com/auth/drive.readonly`,<br />`https://www.googleapis.com/auth/gmail.readonly`<br />2. To use **OAuth client**, configure your [credentials](#authenticate-using-oauth-client). |
| Radius | Each connection represents a single Google Workspace account. |
| Resolution | 1. Credentials from the JSON file specified by the `credentials` parameter in your Steampipe config.<br />2. Credentials from the JSON file specified by the `token_path` parameter in your Steampipe config.<br />3. Credentials from the default json file location (`~/.config/gcloud/application_default_credentials.json`). |

Expand Down Expand Up @@ -107,6 +107,7 @@ You can use client secret credentials to protect the user's data by only grantin
gcloud auth application-default login \
--client-id-file=client_secret.json \
--scopes="\
https://www.googleapis.com/auth/admin.reports.audit.readonly,\
https://www.googleapis.com/auth/calendar.readonly,\
https://www.googleapis.com/auth/contacts.other.readonly,\
https://www.googleapis.com/auth/contacts.readonly,\
Expand Down
187 changes: 187 additions & 0 deletions docs/tables/googleworkspace_admin_reports_activity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---

title: "Steampipe Table: googleworkspace_admin_reports_activity - Query Google Workspace Admin Reports Activity using SQL"
description: "Allows users to query the Google Workspace Admin Reports API to retrieve detailed audit activity logs across various Google Workspace applications."
---

# Table: googleworkspace_admin_reports_activity - Query Google Workspace Admin Reports Activity using SQL

The `googleworkspace_admin_reports_activity` table in Steampipe provides a unified interface to query the Google Workspace Admin Reports API. It surfaces detailed audit logs across all Workspace applications (Drive, Calendar, Keep, Admin console, and more). You can use this table to investigate user actions, system events, and security-related activities within your Workspace environment.

## Table Usage Guide

To use this table, you **must** specify the `application_name` qualifier corresponding to one of the supported Google Workspace apps (the list of all applications is available [here](https://developers.google.com/workspace/admin/reports/reference/rest/v1/activities/list?hl=fr#applicationname). This qualifier scopes the API request to a single application’s audit logs.

You can optionally filter by:

* `time` — filter events before/after a specific timestamp (RFC3339 format).
* `actor_email` — the email of the user or service account performing the action.
* `ip_address` — the source IP of the event.
* `event_names` — names of the audit events (e.g., `create_file`, `deleted`, `created_note`).

**Important Notes**

* **Required Qualifier**: You must include `where application_name = '<app>'` in every query (no default).
* **Time Filter**: For performance, use the optional `time` qualifier to limit the result set to a specific period.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please update the Important Notes section to follow the format we use in other tables? For reference, you can take a look at the gcp_logging_log_entry table in the GCP plugin: link. It would also be helpful to include a link to the list of supported values for the application_name column, if available.


## Examples

### List all Drive events in the last hour

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Retrieve audit events for Google Drive that occurred in the past hour.

```sql+postgres
select
time,
actor_email,
event_names,
param->>'value' as file_name,
ip_address,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param
where
application_name = 'drive'
and param->>'name' = 'doc_title'
and time > now() - interval '1 hour';
```

```sql+sqlite
select
time,
actor_email,
event_names,
param->>'value' as file_name,
ip_address,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param
where
application_name = 'drive'
and param->>'name' = 'doc_title'
and time > datetime('now', '-1 hour');
```

### List all password changes performed by administrators on users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Show all changes of password performed by administrators on users in the last month.

```sql+postgres
select
time,
actor_email,
event_names,
param->>'value' as user_email,
ip_address,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param
where
application_name = 'admin'
and event_names ? 'CHANGE_PASSWORD'
and param->>'name' = 'USER_EMAIL'
and time > now() - interval '1 month';
```

```sql+sqlite
select
time,
actor_email,
event_names,
param->>'value' as user_email,
ip_address,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param
where
application_name = 'admin'
and event_names ? 'CHANGE_PASSWORD'
and param->>'name' = 'USER_EMAIL'
and time > datetime('now', '-1 month');
```

### Show login failures by specific user

Show all failed login attempts by a specific user in the last week.

```sql+postgres
select
time,
event_names,
ip_address
from
googleworkspace_admin_reports_activity
where
application_name = 'login'
and actor_email = 'xxx@xxx.xxx'
and event_names = '["login_failure"]'
and time > now() - '1 week'::interval;
```

```sql+sqlite
select
time,
event_names,
ip_address
from
googleworkspace_admin_reports_activity
where
application_name = 'login'
and actor_email = 'xxx@xxx.xxx'
and event_names = '["login_failure"]'
and time > datetime('now', '-1 week');
```

### Show all connections from a new device

Identify all connections from a new device in the last week.

```sql+postgres
select
time,
actor_email,
event_names,
param1->>'value' as device_id,
param2->>'value' as device_model,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param1
cross join lateral jsonb_array_elements(evt->'parameters') as param2
where
application_name = 'mobile'
and event_names = '["DEVICE_REGISTER_UNREGISTER_EVENT"]'
and param1->>'name' = 'DEVICE_ID'
and param2->>'name' = 'DEVICE_MODEL'
and time > now() - interval '1 day';
```

```sql+sqlite
select
time,
actor_email,
event_names,
param1->>'value' as device_id,
param2->>'value' as device_model,
events
from
googleworkspace_admin_reports_activity as a
cross join lateral jsonb_array_elements(a.events) as evt
cross join lateral jsonb_array_elements(evt->'parameters') as param1
cross join lateral jsonb_array_elements(evt->'parameters') as param2
where
application_name = 'mobile'
and event_names = '["DEVICE_REGISTER_UNREGISTER_EVENT"]'
and param1->>'name' = 'DEVICE_ID'
and param2->>'name' = 'DEVICE_MODEL'
and time > datetime('now', '-1 day');
```
29 changes: 15 additions & 14 deletions googleworkspace/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,21 @@ func Plugin(ctx context.Context) *plugin.Plugin {
NewInstance: ConfigInstance,
},
TableMap: map[string]*plugin.Table{
"googleworkspace_calendar": tableGoogleWorkspaceCalendar(ctx),
"googleworkspace_calendar_event": tableGoogleWorkspaceCalendarEvent(ctx),
"googleworkspace_calendar_my_event": tableGoogleWorkspaceCalendarMyEvent(ctx),
"googleworkspace_drive": tableGoogleWorkspaceDrive(ctx),
"googleworkspace_drive_my_file": tableGoogleWorkspaceDriveMyFile(ctx),
"googleworkspace_gmail_draft": tableGoogleWorkspaceGmailDraft(ctx),
"googleworkspace_gmail_message": tableGoogleWorkspaceGmailMessage(ctx),
"googleworkspace_gmail_my_draft": tableGoogleWorkspaceGmailMyDraft(ctx),
"googleworkspace_gmail_my_message": tableGoogleWorkspaceGmailMyMessage(ctx),
"googleworkspace_gmail_my_settings": tableGoogleWorkspaceGmailMySettings(ctx),
"googleworkspace_gmail_settings": tableGoogleWorkspaceGmailSettings(ctx),
"googleworkspace_people_contact": tableGoogleWorkspacePeopleContact(ctx),
"googleworkspace_people_contact_group": tableGoogleWorkspacePeopleContactGroup(ctx),
"googleworkspace_people_directory_people": tableGoogleWorkspacePeopleDirectoryPeople(ctx),
"googleworkspace_admin_reports_activity": tableGoogleworkspaceAdminReportsActivity(ctx),
"googleworkspace_calendar": tableGoogleWorkspaceCalendar(ctx),
"googleworkspace_calendar_event": tableGoogleWorkspaceCalendarEvent(ctx),
"googleworkspace_calendar_my_event": tableGoogleWorkspaceCalendarMyEvent(ctx),
"googleworkspace_drive": tableGoogleWorkspaceDrive(ctx),
"googleworkspace_drive_my_file": tableGoogleWorkspaceDriveMyFile(ctx),
"googleworkspace_gmail_draft": tableGoogleWorkspaceGmailDraft(ctx),
"googleworkspace_gmail_message": tableGoogleWorkspaceGmailMessage(ctx),
"googleworkspace_gmail_my_draft": tableGoogleWorkspaceGmailMyDraft(ctx),
"googleworkspace_gmail_my_message": tableGoogleWorkspaceGmailMyMessage(ctx),
"googleworkspace_gmail_my_settings": tableGoogleWorkspaceGmailMySettings(ctx),
"googleworkspace_gmail_settings": tableGoogleWorkspaceGmailSettings(ctx),
"googleworkspace_people_contact": tableGoogleWorkspacePeopleContact(ctx),
"googleworkspace_people_contact_group": tableGoogleWorkspacePeopleContactGroup(ctx),
"googleworkspace_people_directory_people": tableGoogleWorkspacePeopleDirectoryPeople(ctx),
},
}

Expand Down
27 changes: 27 additions & 0 deletions googleworkspace/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"google.golang.org/api/gmail/v1"
"google.golang.org/api/option"
"google.golang.org/api/people/v1"
"google.golang.org/api/admin/reports/v1"

"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
)
Expand Down Expand Up @@ -115,6 +116,31 @@ func GmailService(ctx context.Context, d *plugin.QueryData) (*gmail.Service, err
return svc, nil
}

func ReportsService(ctx context.Context, d *plugin.QueryData) (*admin.Service, error) {
// have we already created and cached the service?
serviceCacheKey := "googleworkspace.reports"
if cached, ok := d.ConnectionManager.Cache.Get(serviceCacheKey); ok {
return cached.(*admin.Service), nil
}

// so it was not in cache - create service
opts, err := getSessionConfig(ctx, d)
if err != nil {
return nil, err
}

// Create service
svc, err := admin.NewService(ctx, opts...)
if err != nil {
return nil, err
}

// cache the service
d.ConnectionManager.Cache.Set(serviceCacheKey, svc)
return svc, nil
}


func getSessionConfig(ctx context.Context, d *plugin.QueryData) ([]option.ClientOption, error) {
opts := []option.ClientOption{}

Expand Down Expand Up @@ -199,6 +225,7 @@ func getTokenSource(ctx context.Context, d *plugin.QueryData) (oauth2.TokenSourc
// Authorize the request
config, err := google.JWTConfigFromJSON(
[]byte(credentialContent),
admin.AdminReportsAuditReadonlyScope,
calendar.CalendarReadonlyScope,
drive.DriveReadonlyScope,
gmail.GmailReadonlyScope,
Expand Down
Loading