GSuiteAuditor
G Suite Auditor is an integration that receives Audit logs from G Suite's different applications - admin, drive, calender, and more.
IT Services · GsuiteAuditor
Details
| ID | GSuiteAuditor |
|---|---|
| Provider | |
| Category | IT Services |
| From Version | 5.5.0 |
| Docker Image | demisto/googleapi-python3:1.0.0.115338 |
| Supported Modules | Agentix XSIAM |
README
G Suite Auditor is an integration that receives audit logs from G Suite’s different applications - admin, drive, calendar, and more.
Required Permissions
In order to use the integration you will need:
- Admin email address.
- Service Account with access to the following scope - https://www.googleapis.com/auth/admin.reports.audit.readonly .
For more information, see the integrations description.
For more information about the integration arguments
- Command arguments documentation in Google’s API.
- Application to event names table by Google’s API.
Google’s lag time information
This integration relies on Google’s audit logs which are prone to some data delays. Some results may be partial if data had not arrived due to lag times. The lag time changes depending on the used audit log (from near real-time up to 3 days).
For more information - https://support.google.com/a/answer/7061566?hl=en
Configure G Suite Auditor in Cortex
| Parameter | Required |
|---|---|
| Admin email | True |
| User’s Service Account JSON | True |
| Use system proxy settings | False |
| Trust any certificate (not secure) | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
gsuite-activity-search
Retrieves a list of activities for a specific customer’s account and application.
Base Command
gsuite-activity-search
Input
| Argument Name | Description | Required |
|---|---|---|
| user_key | Profile ID or the user email for which the data should be filtered. Can be ‘all’ for all information, or ‘userKey’ for a user’s unique Google Workspace profile ID or their primary email address. | Optional |
| application_name | Application name for which the events are to be retrieved. Possible values are: access_transparency, admin, calendar, chat, drive, gcp, gplus, groups, groups_enterprise, jamboard, login, meet, mobile, rules, saml, token, user_accounts, context_aware_access, chrome, data_studio, keep. | Required |
| event_name | The name of the event being queried. For a list of event names for each application, see the integration documentation. | Optional |
| filters | A comma-separated list of event parameters and relational operators. For example- ‘API_CLIENT_NAME==111,API_SCOPES=aaa’. The relevant ‘event name’ argument must be supplied to use this argument. |
Optional |
| org_unit_id | ID of the organizational unit to report on. Activity records will be shown only for users who belong to the specified organizational unit. | Optional |
| group_id | Comma-separated group IDs on which user activities are filtered. The response will contain activities for only those users who are a part of at least one of the group IDs mentioned here. For example: “id:abc123,id:xyz456”. To retrieve a group ID, use the ‘gsuite-get-group’ command in the ‘G Suite Admin’ pack. |
Optional |
| actor_ip_address | IP address of the host where the event was performed. | Optional |
| start_time | The beginning of the time range shown in the report. For example - 2010-10-28T10:26:35.000Z. | Optional |
| end_time | The end of the time range shown in the report. For example - 2010-10-28T10:26:35.000Z. | Optional |
| max_results | Maximum number of results to return. Default is 50. | Optional |
| page_token | The token to specify the next page. | Optional |
| admin_email | Email address of the G Suite domain admin. The request is preformed based on this user’s permissions. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GSuite.ActivitySearch.items.id.time | Date | Time the activity occurred. |
| GSuite.ActivitySearch.items.id.uniqueQualifier | String | Unique qualifier if multiple events have the same time. |
| GSuite.ActivitySearch.items.id.applicationName | String | Application name to which the event belongs. |
| GSuite.ActivitySearch.items.id.customerId | String | The unique identifier for a Google Workspace account. |
| GSuite.ActivitySearch.items.actor.callerType | String | The type of actor. |
| GSuite.ActivitySearch.items.actor.key | String | Can be the consumer_key of the requestor for OAuth 2LO API requests or an identifier for robot accounts. |
| GSuite.ActivitySearch.items.events.type | String | Type of event. |
| GSuite.ActivitySearch.items.events.name | String | Name of the event. |
| GSuite.ActivitySearch.items.events.parameters.name | String | The name of the parameter. |
| GSuite.ActivitySearch.items.events.parameters.value | String | String value of the parameter. |
| GSuite.ActivitySearch.items.actor.email | String | The primary email address of the actor. |
| GSuite.ActivitySearch.items.actor.profileId | String | The unique Google Workspace profile ID of the actor. |
| GSuite.ActivitySearch.items.ipAddress | String | IP address of the user performing the action. |
| GSuite.ActivitySearch.items.events.parameters.boolValue | Boolean | Boolean value of the parameter. |
| GSuite.ActivitySearch.items.events.parameters.multiValue | String | String values of the parameter. |
| GSuite.PageToken.ActivitySearch.nextPageToken | String | Token to specify the next page in the list. |
Command Example
!gsuite-activity-search application_name=admin max_results=2
Context Example
{
"GSuite": {
"ActivitySearch": [
{
"actor": {
"callerType": "KEY",
"key": "SYSTEM"
},
"events": [
{
"name": "USER_LICENSE_REVOKE",
"parameters": [
{
"name": "USER_EMAIL",
"value": "user@email.com"
},
{
"name": "PRODUCT_NAME",
"value": "Google Workspace"
},
{
"name": "OLD_VALUE",
"value": "G Suite Business"
}
],
"type": "LICENSES_SETTINGS"
}
],
"id": {
"applicationName": "admin",
"customerId": "11111",
"time": "2021-07-27T02:47:20.894Z",
"uniqueQualifier": "-7168880636905757919"
}
},
{
"actor": {
"callerType": "USER",
"email": "admin@email.com",
"profileId": "103020731686044834269"
},
"events": [
{
"name": "DELETE_USER",
"parameters": [
{
"name": "USER_EMAIL",
"value": "user@email.com"
}
],
"type": "USER_SETTINGS"
}
],
"id": {
"applicationName": "admin",
"customerId": "1111",
"time": "2021-07-27T01:47:40.585Z",
"uniqueQualifier": "-4797090398870165525"
},
"ipAddress": " "
}
],
"PageToken": {
"ActivitySearch": {
"nextPageToken": "A:1627350460585000:-4797090398870165525:207535951991:C02f0zfqw"
}
}
}
}
Human Readable Output
Next Page Token: A:1627350460585000:-4797090398870165525:207535951991:C02f0zfqw
Total Retrieved Activities: 2
Time Application Name ProfileId IpAddress Events 2021-07-27T02:47:20.894Z admin {‘type’: ‘LICENSES_SETTINGS’, ‘name’: ‘USER_LICENSE_REVOKE’, ‘parameters’: [{‘name’: ‘USER_EMAIL’, ‘value’: ‘user@email.com’}, {‘name’: ‘PRODUCT_NAME’, ‘value’: ‘Google Workspace’}, {‘name’: ‘OLD_VALUE’, ‘value’: ‘G Suite Business’}]} 2021-07-27T01:47:40.585Z admin admin@email.com 103020731686044834269 - {‘type’: ‘USER_SETTINGS’, ‘name’: ‘DELETE_USER’, ‘parameters’: [{‘name’: ‘USER_EMAIL’, ‘value’: ‘user@email.com’}]}
Configuration parameters
credentials— Admin emailproxy— Use system proxy settingsinsecure— Trust any certificate (not secure)
Commands (1)
-
gsuite-activity-searchRetrieves a list of activities for a specific customer's account and application.
# import demistomock as demisto from CommonServerPython import * # noqa # pylint: disable=unused-wildcard-import from CommonServerUserPython import * # noqa from GSuiteApiModule import * # noqa: E402 """ IMPORTS """ from typing import Any import urllib3 # Disable insecure warnings urllib3.disable_warnings() ADMIN_EMAIL = None """ CONSTANTS """ OUTPUT_PREFIX: dict[str, str] = { "ACTIVITY_LIST": "GSuite.ActivitySearch", "ACTIVITY_LIST_PAGE_TOKEN": "GSuite.PageToken.ActivitySearch", } REQ_URL = "https://admin.googleapis.com/" URL_SUFFIX = "admin/reports/v1/activity/users/{}/applications/{}" SCOPE = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"] DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR DATE_MILISEC_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" """ HELPER FUNCTIONS """ def is_email_valid(email: str) -> bool: """ Validates provided email is valid or not. :param email: email string. :return: True if email is in valid format. """ return bool(re.match(emailRegex, email)) def prepare_args_for_activities_list(args: dict[str, str]) -> dict[str, str]: """ Prepares arguments for gsuite-activity-search command. :param args: Command arguments. :return: Prepared arguments. """ return GSuiteClient.remove_empty_entities( { "eventName": args.get("event_name"), "filters": args.get("filters"), "orgUnitId": args.get("org_unit_id"), "groupIdFilter": args.get("group_id"), "actorIpAddress": args.get("actor_ip_address"), "startTime": args.get("start_time"), "endTime": args.get("end_time"), "maxResults": GSuiteClient.validate_get_int( args.get("max_results"), "The argument max_results must be a positive integer." ), "pageToken": args.get("page_token"), } ) def prepare_readable_items(items: list[dict[str, Any]]) -> list[dict[str, Any]]: readable_items = [ { "Time": item.get("id", {}).get("time"), "Application Name": item.get("id", {}).get("applicationName"), "Email": item.get("actor", {}).get("email"), "ProfileId": item.get("actor", {}).get("profileId"), "IpAddress": item.get("ipAddress", ""), "Events": item["events"], } for item in items ] return GSuiteClient.remove_empty_entities(readable_items) def prepare_output_for_activities_list(response: dict[str, Any]) -> dict[str, Any]: """ prepares context output for gsuite-activity-search. :param response: API response. :return: output dictionary. """ output_items = [ {"id": item["id"], "actor": item["actor"], "ipAddress": item.get("ipAddress", []), "events": item["events"]} for item in response.get("items", []) ] return { "GSuite.ActivitySearch": GSuiteClient.remove_empty_entities(output_items), "GSuite.PageToken.ActivitySearch": {"nextPageToken": response["nextPageToken"]} if response.get("nextPageToken", "") else {}, } def prepare_gsuite_client(params: dict) -> GSuiteClient: user_service_account = params.get("credentials", {}).get("password") service_account_dict = GSuiteClient.safe_load_non_strict_json(user_service_account) verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) headers = {"Content-Type": "application/json"} # prepare client class object gsuite_client = GSuiteClient(service_account_dict, base_url=REQ_URL, verify=verify_certificate, proxy=proxy, headers=headers) return gsuite_client @logger def test_module(client: GSuiteClient) -> str: """ Performs test connectivity by valid http response :param client: client object which is used to get response from api. :return: raise ValueError if any error occurred during connection :raises DemistoException: If there is any other issues while making the http call. """ with GSuiteClient.http_exception_handler(): if ADMIN_EMAIL: suffix = URL_SUFFIX.format("all", "admin") client.http_request(url_suffix=suffix, method="GET", params={"max_results": "1"}) else: return_results("Please insert Admin Email parameter for the test to run") return "ok" """ COMMAND FUNCTIONS """ def activities_list_command(client: GSuiteClient, args: dict[str, Any]) -> CommandResults: """ Prints all activities in the G Suite instance. :param client: client object which is used to get response from api :param args: command arguments. :return: CommandResults object with context and human-readable. """ arguments = prepare_args_for_activities_list(args) response = client.http_request( url_suffix=URL_SUFFIX.format(args.get("user_key", "all"), args.get("application_name")), params=arguments ) # Readable Output readable_items = prepare_readable_items(response.get("items", [])) readable_output = f'### Next Page Token: {response["nextPageToken"]}\n' if response.get("nextPageToken") else "" readable_output += ( tableToMarkdown( "Total Retrieved {}: {}".format("Activities", len(response.get("items", []))), readable_items, ["Time", "Application Name", "Email", "ProfileId", "IpAddress", "Events"], ) if response.get("items") else "No activities found for the given argument(s). " ) # Context context_outputs = prepare_output_for_activities_list(response) return CommandResults(outputs=context_outputs, readable_output=readable_output, raw_response=response) """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ command = demisto.command() demisto.info(f"Command being called is {command}") try: global ADMIN_EMAIL params = demisto.params() gsuite_client = prepare_gsuite_client(params) # Trim the arguments args = GSuiteClient.strip_dict(demisto.args()) ADMIN_EMAIL = args.get("admin_email") if args.get("admin_email") else params.get("credentials", {}).get("identifier") # Validation of ADMIN_EMAIL if ADMIN_EMAIL and not is_email_valid(ADMIN_EMAIL): raise ValueError("Invalid value of argument/parameter Admin Email.") gsuite_client.set_authorized_http(scopes=SCOPE, subject=ADMIN_EMAIL) # This is the call made when pressing the integration Test button. if command == "test-module": result = test_module(gsuite_client) return_results(result) elif command == "gsuite-activity-search": return_results(activities_list_command(gsuite_client, args)) # Log exceptions except Exception as e: return_error(f"Error: {e!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()