Skip to content

Commit 1302d85

Browse files
dandyecopybara-github
authored andcommitted
v1alpha samples for: Create (Ref) List, Create/List Rule(s), Get UDM Event
PiperOrigin-RevId: 604660320
1 parent ec94275 commit 1302d85

File tree

6 files changed

+540
-0
lines changed

6 files changed

+540
-0
lines changed

common/project_id.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
"""Support for Project ID for v1alpha Chronicle API calls."""
16+
import argparse
17+
18+
19+
def add_argument_project_id(parser: argparse.ArgumentParser):
20+
"""Adds a shared command-line argument to all the sample modules."""
21+
parser.add_argument(
22+
"-p", "--project_id", type=str, required=True,
23+
help="Your BYOP, project id",
24+
)

common/project_instance.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
"""Support for Project INSTANCE for v1alpha Chronicle API calls."""
16+
17+
import argparse
18+
19+
20+
def add_argument_project_instance(parser: argparse.ArgumentParser):
21+
"""Adds a shared command-line argument to all the sample modules."""
22+
parser.add_argument(
23+
"-i",
24+
"--project_instance",
25+
type=str,
26+
required=True,
27+
help="Customer ID for Chronicle instance",
28+
)

detect/v1alpha/create_rule.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2024 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
r"""Executable and reusable sample for creating a detection rule.
18+
19+
HTTP request
20+
POST https://chronicle.googleapis.com/v1alpha/{parent}/rules
21+
22+
python3 -m detect.v1alpha.create_rule \
23+
--project_instance $project_instance \
24+
--project_id $PROJECT_ID \
25+
--rule_file=./ip_in_abuseipdb_blocklist.yaral
26+
27+
Requires the following IAM permission on the parent resource:
28+
chronicle.rules.create
29+
30+
API reference:
31+
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.rules/create
32+
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.rules#Rule
33+
"""
34+
35+
import argparse
36+
import json
37+
from typing import Any, Mapping
38+
39+
from google.auth.transport import requests
40+
41+
from common import chronicle_auth
42+
from common import project_id
43+
from common import project_instance
44+
from common import regions
45+
46+
SCOPES = [
47+
"https://www.googleapis.com/auth/cloud-platform",
48+
]
49+
50+
51+
def create_rule(
52+
http_session: requests.AuthorizedSession,
53+
proj_id: str,
54+
proj_instance: str,
55+
proj_region: str,
56+
rule_file_path: str,
57+
) -> Mapping[str, Any]:
58+
"""Creates a new detection rule to find matches in logs.
59+
60+
Args:
61+
http_session: Authorized session for HTTP requests.
62+
proj_id: GCP project id or number to which the target instance belongs.
63+
proj_instance: Customer ID (uuid with dashes) for the Chronicle instance.
64+
proj_region: region in which the target project is located.
65+
rule_file_path: Content of the new detection rule, used to evaluate logs.
66+
67+
Returns:
68+
New detection rule.
69+
70+
Raises:
71+
requests.exceptions.HTTPError: HTTP request resulted in an error
72+
(response.status_code >= 400).
73+
"""
74+
# pylint: disable-next=line-too-long
75+
parent = f"projects/{proj_id}/locations/{proj_region}/instances/{proj_instance}"
76+
url = f"https://{proj_region}-chronicle.googleapis.com/v1alpha/{parent}/rules"
77+
body = {
78+
"text": rule_file_path.read(),
79+
}
80+
response = http_session.request("POST", url, json=body)
81+
# Expected server response:
82+
# {
83+
# # pylint: disable=line-too-long
84+
# "name": "projects/{project}/locations/{location}/instances/{instance}/rules/{rule_id}",
85+
# "revisionId": "v_{10_digits}_{9_digits}",
86+
# "displayName": "{rule_name}",
87+
# "text": "{rule_content}",
88+
# "author": str,
89+
# "severity": {
90+
# "displayName": str
91+
# },
92+
# "metadata": {
93+
# "{key_1}": "{value_1}",
94+
# ...
95+
# },
96+
# "createTime": "yyyy-MM-ddThh:mm:ss.ssssssZ",
97+
# "revisionCreateTime": "yyyy-MM-ddThh:mm:ss.ssssssZ"
98+
# "compilationState": "SUCCEEDED",
99+
# "type": "{{SINGLE,MULTI}_EVENT,RULE_TYPE_UNSPECIFIED}",
100+
# "referenceLists": [str],
101+
# "allowedRunFrequencies": [
102+
# str,
103+
# ...
104+
# ],
105+
# "etag": str
106+
# }
107+
if response.status_code >= 400:
108+
print(response.text)
109+
response.raise_for_status()
110+
return response.json()
111+
112+
113+
if __name__ == "__main__":
114+
parser = argparse.ArgumentParser()
115+
# common
116+
chronicle_auth.add_argument_credentials_file(parser)
117+
project_instance.add_argument_project_instance(parser)
118+
project_id.add_argument_project_id(parser)
119+
regions.add_argument_region(parser)
120+
# local
121+
parser.add_argument(
122+
"-f",
123+
"--rule_file",
124+
type=argparse.FileType("r"),
125+
required=True,
126+
# File example: python3 create_rule.py -f <path>
127+
# STDIN example: cat rule.txt | python3 create_rule.py -f -
128+
help="path of a file with the desired rule's content, or - for STDIN",
129+
)
130+
args = parser.parse_args()
131+
132+
auth_session = chronicle_auth.initialize_http_session(
133+
args.credentials_file,
134+
SCOPES
135+
)
136+
new_rule = create_rule(auth_session,
137+
args.project_id,
138+
args.project_instance,
139+
args.region,
140+
args.rule_file)
141+
print(json.dumps(new_rule, indent=2))

detect/v1alpha/list_rules.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2024 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
"""Executable and reusable sample for retrieving a list of rules."""
18+
19+
import argparse
20+
import json
21+
from typing import Mapping, Any
22+
23+
from google.auth.transport import requests
24+
25+
from common import chronicle_auth
26+
from common import project_id
27+
from common import project_instance
28+
from common import regions
29+
30+
SCOPES = [
31+
"https://www.googleapis.com/auth/cloud-platform",
32+
]
33+
34+
35+
def list_rules(
36+
http_session: requests.AuthorizedSession,
37+
proj_id: str,
38+
proj_instance: str,
39+
proj_region: str,
40+
) -> Mapping[str, Any]:
41+
"""Gets a list of rules.
42+
43+
Args:
44+
http_session: Authorized session for HTTP requests.
45+
proj_id: GCP project id or number to which the target instance belongs.
46+
proj_instance: Customer ID (uuid with dashes) for the Chronicle instance.
47+
proj_region: region in which the target project is located.
48+
Returns:
49+
Array containing information about rules.
50+
Raises:
51+
requests.exceptions.HTTPError: HTTP request resulted in an error
52+
(response.status_code >= 400).
53+
"""
54+
# pylint: disable-next=line-too-long
55+
parent = f"projects/{proj_id}/locations/{proj_region}/instances/{proj_instance}"
56+
url = f"https://{proj_region}-chronicle.googleapis.com/v1alpha/{parent}/rules"
57+
58+
response = http_session.request("GET", url)
59+
if response.status_code >= 400:
60+
print(response.text)
61+
response.raise_for_status()
62+
return response.json()
63+
64+
65+
if __name__ == "__main__":
66+
parser = argparse.ArgumentParser()
67+
chronicle_auth.add_argument_credentials_file(parser)
68+
project_instance.add_argument_project_instance(parser)
69+
project_id.add_argument_project_id(parser)
70+
regions.add_argument_region(parser)
71+
args = parser.parse_args()
72+
session = chronicle_auth.initialize_http_session(
73+
args.credentials_file,
74+
SCOPES
75+
)
76+
rules = list_rules(
77+
session,
78+
args.project_id,
79+
args.project_instance,
80+
args.region
81+
)
82+
print(json.dumps(rules, indent=2))

ingestion/v1alpha/get_udm_event.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2024 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# pylint: disable=line-too-long
18+
r"""Executable and reusable v1alpha API sample for getting a UDM event by ID.
19+
20+
API reference:
21+
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.events/get
22+
"""
23+
# pylint: enable=line-too-long
24+
25+
import argparse
26+
import json
27+
28+
from google.auth.transport import requests
29+
30+
from common import chronicle_auth
31+
from common import project_id
32+
from common import project_instance
33+
from common import regions
34+
35+
SCOPES = [
36+
"https://www.googleapis.com/auth/cloud-platform",
37+
]
38+
39+
40+
def get_udm_event(
41+
http_session: requests.AuthorizedSession,
42+
proj_id: str,
43+
proj_instance: str,
44+
proj_region: str,
45+
event_id: str):
46+
"""Get a UDM event by metadata.id.
47+
48+
A Unified Data Model (UDM) event is a structured representation of an event
49+
regardless of the log source.
50+
51+
Args:
52+
http_session: Authorized session for HTTP requests.
53+
proj_id: GCP project id or number to which the target instance belongs.
54+
proj_instance: Customer ID (uuid with dashes) for the Chronicle instance.
55+
proj_region: region in which the target project is located.
56+
event_id: URL-encoded Base64 for the UDM Event ID.
57+
Returns:
58+
dict/json respresentation of UDM Event
59+
Raises:
60+
requests.exceptions.HTTPError: HTTP request resulted in an error
61+
(response.status_code >= 400).
62+
63+
Requires the following IAM permission on the parent resource:
64+
chronicle.events.get
65+
66+
https://cloud.google.com/chronicle/docs/reference/rest/v1alpha/projects.locations.instances.events/get
67+
"""
68+
# pylint: disable=line-too-long
69+
parent = f"projects/{proj_id}/locations/{proj_region}/instances/{proj_instance}"
70+
url = f"https://{proj_region}-chronicle.googleapis.com/v1alpha/{parent}/events/{event_id}"
71+
# pylint: enable=line-too-long
72+
73+
response = http_session.request("GET", url)
74+
if response.status_code >= 400:
75+
print(response.text)
76+
response.raise_for_status()
77+
return response.json()
78+
79+
80+
if __name__ == "__main__":
81+
parser = argparse.ArgumentParser()
82+
# common
83+
chronicle_auth.add_argument_credentials_file(parser)
84+
project_instance.add_argument_project_instance(parser)
85+
project_id.add_argument_project_id(parser)
86+
regions.add_argument_region(parser)
87+
# local
88+
parser.add_argument(
89+
"--event_id",
90+
type=str,
91+
required=True,
92+
help=("URL-encoded Base64 ID of the Event"),
93+
)
94+
args = parser.parse_args()
95+
96+
auth_session = chronicle_auth.initialize_http_session(
97+
args.credentials_file,
98+
SCOPES,
99+
)
100+
event = get_udm_event(
101+
auth_session,
102+
args.project_id,
103+
args.project_instance,
104+
args.region,
105+
args.event_id)
106+
print(json.dumps(event, indent=2))

0 commit comments

Comments
 (0)