-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
v1alpha samples for: Create Ref List, Rule, UDM Event
PiperOrigin-RevId: 599597439
- Loading branch information
1 parent
ec94275
commit 46641d0
Showing
7 changed files
with
637 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
"""Support for Project ID for v1alpha Chronicle API calls.""" | ||
import argparse | ||
|
||
|
||
def add_argument_project_id(parser: argparse.ArgumentParser): | ||
"""Adds a shared command-line argument to all the sample modules.""" | ||
parser.add_argument( | ||
"-p", "--project_id", type=str, required=True, | ||
help="Your BYOP, project id", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
"""Support for Project INSTANCE for v1alpha Chronicle API calls.""" | ||
|
||
import argparse | ||
|
||
|
||
def add_argument_project_instance(parser: argparse.ArgumentParser): | ||
"""Adds a shared command-line argument to all the sample modules.""" | ||
parser.add_argument( | ||
"-g", | ||
"--project_instance", | ||
type=str, | ||
required=True, | ||
help="Customer ID for Chronicle instance", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
r"""Executable and reusable sample for creating a detection rule. | ||
HTTP request | ||
POST https://chronicle.googleapis.com/v1alpha/{parent}/rules | ||
python3 -m detect.v1alpha.create_rule \ | ||
--project_instance $project_instance \ | ||
--project_id $PROJECT_ID \ | ||
--rule_file=./ip_in_abuseipdb_blocklist.yaral | ||
Requires the following IAM permission on the parent resource: | ||
chronicle.rules.create | ||
API reference: | ||
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.rules/create | ||
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.rules#Rule | ||
""" | ||
|
||
import argparse | ||
import json | ||
from typing import Any, Mapping | ||
|
||
from google.auth.transport import requests | ||
|
||
from common import chronicle_auth | ||
from common import project_id | ||
from common import project_instance | ||
from common import regions | ||
|
||
|
||
INGESTION_API_BASE_URL = "https://malachiteingestion-pa.googleapis.com" | ||
AUTHORIZATION_SCOPES = ["https://www.googleapis.com/auth/malachite-ingestion"] | ||
|
||
SCOPES = [ | ||
"https://www.googleapis.com/auth/cloud-platform", | ||
] | ||
|
||
|
||
def create_rule( | ||
http_session: requests.AuthorizedSession, | ||
rule_file_path: str, | ||
) -> Mapping[str, Any]: | ||
"""Creates a new detection rule to find matches in logs. | ||
Args: | ||
http_session: Authorized session for HTTP requests. | ||
rule_file_path: Content of the new detection rule, used to evaluate logs. | ||
Returns: | ||
New detection rule. | ||
Raises: | ||
requests.exceptions.HTTPError: HTTP request resulted in an error | ||
(response.status_code >= 400). | ||
""" | ||
parent = f"projects/{args.project_id}/locations/{args.region}/instances/{args.project_instance}" | ||
url = f"https://{args.region}-chronicle.googleapis.com/v1alpha/{parent}/rules" | ||
body = { | ||
"text": rule_file_path.read(), | ||
} | ||
response = http_session.request("POST", url, json=body) | ||
# Expected server response: | ||
# { | ||
# # pylint: disable=line-too-long | ||
# "name": "projects/{project}/locations/{location}/instances/{instance}/rules/{rule_id}", | ||
# "revisionId": "v_{10_digits}_{9_digits}", | ||
# "displayName": "{rule_name}", | ||
# "text": "{rule_content}", | ||
# "author": str, | ||
# "severity": { | ||
# "displayName": str | ||
# }, | ||
# "metadata": { | ||
# "{key_1}": "{value_1}", | ||
# ... | ||
# }, | ||
# "createTime": "yyyy-MM-ddThh:mm:ss.ssssssZ", | ||
# "revisionCreateTime": "yyyy-MM-ddThh:mm:ss.ssssssZ" | ||
# "compilationState": "SUCCEEDED", | ||
# "type": "{{SINGLE,MULTI}_EVENT,RULE_TYPE_UNSPECIFIED}", | ||
# "referenceLists": [str], | ||
# "allowedRunFrequencies": [ | ||
# str, | ||
# ... | ||
# ], | ||
# "etag": str | ||
# } | ||
if response.status_code >= 400: | ||
print(response.text) | ||
response.raise_for_status() | ||
return response.json() | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
# common | ||
chronicle_auth.add_argument_credentials_file(parser) | ||
project_instance.add_argument_project_instance(parser) | ||
project_id.add_argument_project_id(parser) | ||
regions.add_argument_region(parser) | ||
# local | ||
parser.add_argument( | ||
"-f", | ||
"--rule_file", | ||
type=argparse.FileType("r"), | ||
required=True, | ||
# File example: python3 create_rule.py -f <path> | ||
# STDIN example: cat rule.txt | python3 create_rule.py -f - | ||
help="path of a file with the desired rule's content, or - for STDIN", | ||
) | ||
args = parser.parse_args() | ||
|
||
auth_session = chronicle_auth.initialize_http_session( | ||
args.credentials_file, | ||
SCOPES | ||
) | ||
new_rule = create_rule(auth_session, args.rule_file) | ||
print(json.dumps(new_rule, indent=2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
"""Executable and reusable sample for retrieving a list of rules.""" | ||
|
||
import argparse | ||
import json | ||
from typing import Mapping, Any | ||
|
||
from google.auth.transport import requests | ||
|
||
from common import chronicle_auth | ||
from common import project_id | ||
from common import project_instance | ||
from common import regions | ||
|
||
SCOPES = [ | ||
"https://www.googleapis.com/auth/cloud-platform", | ||
] | ||
|
||
|
||
def list_rules(http_session: requests.AuthorizedSession) -> Mapping[str, Any]: | ||
"""Gets a list of rules. | ||
Args: | ||
http_session: Authorized session for HTTP requests. | ||
Returns: | ||
Array containing each line of the feed's content. | ||
Raises: | ||
requests.exceptions.HTTPError: HTTP request resulted in an error | ||
(response.status_code >= 400). | ||
""" | ||
parent = f"projects/{args.project_id}/locations/{args.region}/instances/{args.project_instance}" | ||
url = f"https://{args.region}-chronicle.googleapis.com/v1alpha/{parent}/rules" | ||
|
||
response = http_session.request("GET", url) | ||
if response.status_code >= 400: | ||
print(response.text) | ||
response.raise_for_status() | ||
return response.json() | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
chronicle_auth.add_argument_credentials_file(parser) | ||
project_instance.add_argument_project_instance(parser) | ||
project_id.add_argument_project_id(parser) | ||
regions.add_argument_region(parser) | ||
args = parser.parse_args() | ||
session = chronicle_auth.initialize_http_session( | ||
args.credentials_file, | ||
SCOPES | ||
) | ||
print(json.dumps(list_rules(session), indent=2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
r"""Executable and reusable sample for ingesting events in UDM format. | ||
The Unified Data Model (UDM) is a way of representing events across all log | ||
sources. See | ||
https://cloud.google.com/chronicle/docs/unified-data-model/udm-field-list for a | ||
description of UDM fields, and see | ||
https://cloud.google.com/chronicle/docs/unified-data-model/format-events-as-udm | ||
for how to describe a log as an event in UDM format. | ||
This command accepts a path to a file (--json_events_file) that contains an | ||
array of JSON formatted events in UDM format. See | ||
./example_input/sample_udm_events.json for an example. | ||
So, assuming you've created a credentials file at $HOME/.chronicle_credentials.json, | ||
and you are using environment variables for your PROJECT_INSTANCE and PROJECT_ID, | ||
you can run this command using the sample input like so: | ||
Sample Command: | ||
python3 -m ingestion.v1alpha.create_udm_events \ | ||
--project_instance $PROJECT_INSTANCE \ | ||
--project_id $PROJECT_ID \ | ||
--json_events_file=./ingestion/example_input/sample_udm_events.json | ||
API reference: | ||
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.events/import | ||
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.events/import#EventsInlineSource | ||
https://cloud.google.com/chronicle/docs/reference/udm-field-list | ||
https://cloud.google.com/chronicle/docs/unified-data-model/udm-usage | ||
""" | ||
|
||
import argparse | ||
import json | ||
|
||
from google.auth.transport import requests | ||
|
||
from common import chronicle_auth | ||
from common import project_id | ||
from common import project_instance | ||
from common import regions | ||
|
||
|
||
INGESTION_API_BASE_URL = "https://malachiteingestion-pa.googleapis.com" | ||
AUTHORIZATION_SCOPES = ["https://www.googleapis.com/auth/malachite-ingestion"] | ||
|
||
SCOPES = [ | ||
"https://www.googleapis.com/auth/cloud-platform", | ||
] | ||
|
||
|
||
def create_udm_events( | ||
http_session: requests.AuthorizedSession, json_events: str | ||
) -> None: | ||
"""Sends a collection of UDM events to the Chronicle backend for ingestion. | ||
A Unified Data Model (UDM) event is a structured representation of an event | ||
regardless of the log source. | ||
Args: | ||
http_session: Authorized session for HTTP requests. | ||
json_events: A collection of UDM events in (serialized) JSON format. | ||
Raises: | ||
requests.exceptions.HTTPError: HTTP request resulted in an error | ||
(response.status_code >= 400). | ||
Requires the following IAM permission on the parent resource: | ||
chronicle.events.import | ||
POST https://chronicle.googleapis.com/v1alpha/{parent}/events:import | ||
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.events/import | ||
""" | ||
parent = f"projects/{args.project_id}/locations/{args.region}/instances/{args.project_instance}" | ||
url = f"https://{args.region}-chronicle.googleapis.com/v1alpha/{parent}/events:import" | ||
|
||
body = { | ||
"inline_source": { | ||
"events": [{ | ||
"udm": json.loads(json_events)[0], | ||
}] | ||
} | ||
} | ||
|
||
response = http_session.request("POST", url, json=body) | ||
if response.status_code >= 400: | ||
print(body) | ||
print(response.text) | ||
response.raise_for_status() | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
# common | ||
chronicle_auth.add_argument_credentials_file(parser) | ||
project_instance.add_argument_project_instance(parser) | ||
project_id.add_argument_project_id(parser) | ||
regions.add_argument_region(parser) | ||
# local | ||
parser.add_argument( | ||
"--json_events_file", | ||
type=argparse.FileType("r"), | ||
required=True, | ||
help=( | ||
'path to a file (or "-" for STDIN) containing a list of UDM ' | ||
"events in json format" | ||
), | ||
) | ||
args = parser.parse_args() | ||
auth_session = chronicle_auth.initialize_http_session( | ||
args.credentials_file, | ||
SCOPES, | ||
) | ||
create_udm_events(auth_session, args.json_events_file.read()) |
Oops, something went wrong.