Skip to content

Commit a749460

Browse files
authored
Merge pull request #220 from UncoderIO/gis-9071
GIS 9071 Added new platform Falco
2 parents 4c4f244 + cca40d9 commit a749460

File tree

9 files changed

+249
-0
lines changed

9 files changed

+249
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
platform: Falco
2+
source: aws_cloudtrail
3+
4+
field_mapping:
5+
eventSource: ct.src
6+
eventName: ct.name
7+
errorCode: ct.error
8+
RequestParameters: json.value[/requestParameters]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
platform: Falco
2+
source: default
3+
4+
5+
field_mapping:
6+
{}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from app.translator.platforms.falco.renders.falco import FalcoRuleRender # noqa: F401
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from app.translator.core.models.platform_details import PlatformDetails
2+
3+
FALCO_RULE_DETAILS = {
4+
"platform_id": "falco-yaml-rule",
5+
"name": "Falco YAML Rule",
6+
"platform_name": "Rule (YAML)",
7+
"group_id": "falco",
8+
"group_name": "Falco",
9+
}
10+
11+
falco_rule_details = PlatformDetails(**FALCO_RULE_DETAILS)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from typing import ClassVar
2+
3+
from app.translator.core.custom_types.values import ValueType
4+
from app.translator.core.escape_manager import EscapeManager
5+
from app.translator.core.models.escape_details import EscapeDetails
6+
7+
8+
class FalcoRuleEscapeManager(EscapeManager):
9+
escape_map: ClassVar[dict[str, list[EscapeDetails]]] = {
10+
ValueType.regex_value: [
11+
EscapeDetails(pattern=r"([$^*+()\[\]{}|.?\-\\])", escape_symbols=r"\\\1"),
12+
EscapeDetails(pattern=r"(')", escape_symbols=r"'\1"),
13+
]
14+
}
15+
16+
17+
falco_rule_escape_manager = FalcoRuleEscapeManager()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from app.translator.core.mapping import BaseStrictLogSourcesPlatformMappings, LogSourceSignature
2+
from app.translator.platforms.falco.const import falco_rule_details
3+
4+
5+
class FalcoRuleLogSourceSignature(LogSourceSignature):
6+
def __str__(self) -> str:
7+
return ""
8+
9+
def is_suitable(self) -> bool:
10+
return True
11+
12+
13+
class FalcoRuleMappings(BaseStrictLogSourcesPlatformMappings):
14+
def prepare_log_source_signature(self, mapping: dict) -> FalcoRuleLogSourceSignature: # noqa: ARG002
15+
return FalcoRuleLogSourceSignature()
16+
17+
18+
falco_rule_mappings = FalcoRuleMappings(platform_dir="falco", platform_details=falco_rule_details)

uncoder-core/app/translator/platforms/falco/renders/__init__.py

Whitespace-only changes.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
"""
2+
Uncoder IO Community Edition License
3+
-----------------------------------------------------------------
4+
Copyright (c) 2024 SOC Prime, Inc.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-----------------------------------------------------------------
18+
"""
19+
from typing import ClassVar, Optional
20+
21+
import yaml
22+
23+
from app.translator.const import DEFAULT_VALUE_TYPE
24+
from app.translator.core.custom_types.values import ValueType
25+
from app.translator.core.mapping import LogSourceSignature, SourceMapping
26+
from app.translator.core.models.platform_details import PlatformDetails
27+
from app.translator.core.models.query_container import MetaInfoContainer
28+
from app.translator.core.models.query_tokens.field import Field
29+
from app.translator.core.render import BaseFieldValueRender, PlatformQueryRender
30+
from app.translator.core.str_value_manager import StrValueManager
31+
from app.translator.managers import render_manager
32+
from app.translator.platforms.falco.const import falco_rule_details
33+
from app.translator.platforms.falco.mapping import FalcoRuleMappings, falco_rule_mappings
34+
from app.translator.platforms.falco.str_value_manager import falco_rule_str_value_manager
35+
36+
37+
class FalcoRuleFieldValueRender(BaseFieldValueRender):
38+
details = falco_rule_details
39+
str_value_manager: StrValueManager = falco_rule_str_value_manager
40+
41+
@staticmethod
42+
def _wrap_str_value(value: str) -> str:
43+
return f'"{value}"'
44+
45+
@staticmethod
46+
def _wrap_int_value(value: str) -> str:
47+
return f'"{value}"'
48+
49+
def equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
50+
if isinstance(value, list):
51+
return f"({self.or_token.join([self.equal_modifier(field=field, value=v) for v in value])})"
52+
return f"{field} = {self._pre_process_value(field, value, wrap_str=True)}"
53+
54+
def not_equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
55+
if isinstance(value, list):
56+
return f"({self.or_token.join([self.not_equal_modifier(field=field, value=v) for v in value])})"
57+
return f"{field} != {self._pre_process_value(field, value, wrap_str=True)}"
58+
59+
def less_modifier(self, field: str, value: int) -> str:
60+
return f"{field} < {self._pre_process_value(field, value)}"
61+
62+
def less_or_equal_modifier(self, field: str, value: int) -> str:
63+
return f"{field} <= {self._pre_process_value(field, value)}"
64+
65+
def greater_modifier(self, field: str, value: int) -> str:
66+
return f"{field} > {self._pre_process_value(field, value)}"
67+
68+
def greater_or_equal_modifier(self, field: str, value: int) -> str:
69+
return f"{field} >= {self._pre_process_value(field, value)}"
70+
71+
def contains_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
72+
if isinstance(value, list):
73+
return f"({self.or_token.join([self.contains_modifier(field=field, value=v) for v in value])})"
74+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
75+
return f"{field} contains {value}"
76+
77+
def endswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
78+
if isinstance(value, list):
79+
return f"({self.or_token.join([self.endswith_modifier(field=field, value=v) for v in value])})"
80+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
81+
return f"{field} endswith {value}"
82+
83+
def startswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
84+
if isinstance(value, list):
85+
return f"({self.or_token.join([self.startswith_modifier(field=field, value=v) for v in value])})"
86+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
87+
return f"{field} startswith {value}"
88+
89+
def regex_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
90+
if isinstance(value, list):
91+
return f"({self.or_token.join(self.regex_modifier(field=field, value=v) for v in value)})"
92+
regex_str = self._pre_process_value(field, value, value_type=ValueType.regex_value)
93+
return f"{field} regex '{regex_str}'"
94+
95+
def is_none(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
96+
if isinstance(value, list):
97+
return f"({self.or_token.join(self.is_none(field=field, value=v) for v in value)})"
98+
return f"{field} exists"
99+
100+
101+
@render_manager.register
102+
class FalcoRuleRender(PlatformQueryRender):
103+
details: PlatformDetails = falco_rule_details
104+
mappings: FalcoRuleMappings = falco_rule_mappings
105+
106+
or_token = "or"
107+
and_token = "and"
108+
not_token = "not"
109+
110+
comment_symbol = "//"
111+
112+
field_value_render = FalcoRuleFieldValueRender(or_token=or_token)
113+
114+
priority_map: ClassVar[dict[str, str]] = {
115+
"unspecified": "NOTICE",
116+
"info": "INFORMATIONAL",
117+
"low": "WARNING",
118+
"medium": "ERROR",
119+
"high": "ERROR",
120+
"critical": "CRITICAL",
121+
}
122+
123+
def generate_prefix(self, log_source_signature: Optional[LogSourceSignature], functions_prefix: str = "") -> str: # noqa: ARG002
124+
return ""
125+
126+
def generate_output(self, fields: list[Field], unmapped_fields: list[str], source_mapping: SourceMapping) -> str:
127+
extra_fields = []
128+
for field in fields:
129+
if field.source_name in unmapped_fields:
130+
extra_fields.append(field.source_name)
131+
elif generic_field_name := field.get_generic_field_name(source_mapping.source_id):
132+
extra_field = source_mapping.fields_mapping.get_platform_field_name(generic_field_name)
133+
if extra_field:
134+
extra_fields.append(extra_field)
135+
extra_fields = [f"{field.replace('.', '_')}=%{field}" for field in extra_fields]
136+
return f"shell in a container (container_name=%container.name {' '.join(extra_fields)})"
137+
138+
def finalize_query(
139+
self,
140+
prefix: str,
141+
query: str,
142+
functions: str,
143+
meta_info: Optional[MetaInfoContainer] = None,
144+
source_mapping: Optional[SourceMapping] = None,
145+
not_supported_functions: Optional[list] = None,
146+
unmapped_fields: Optional[list[str]] = None,
147+
*args, # noqa: ARG002
148+
**kwargs, # noqa: ARG002
149+
) -> str:
150+
query = self._join_query_parts(prefix, query, functions)
151+
rule = {
152+
"rule": meta_info.title or "Falco Rule",
153+
"condition": query,
154+
"desc": meta_info.description or "Falco Rule",
155+
"output": self.generate_output(meta_info.query_fields, unmapped_fields or [], source_mapping),
156+
"priority": self.priority_map.get(meta_info.severity or "medium"),
157+
}
158+
rule_str = yaml.dump(rule, default_flow_style=False, sort_keys=False)
159+
rule_str = self.wrap_with_meta_info(rule_str, meta_info)
160+
rule_str = self.wrap_with_unmapped_fields(rule_str, unmapped_fields)
161+
return self.wrap_with_not_supported_functions(rule_str, not_supported_functions)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Uncoder IO Community Edition License
3+
-----------------------------------------------------------------
4+
Copyright (c) 2024 SOC Prime, Inc.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-----------------------------------------------------------------
18+
"""
19+
from app.translator.core.str_value_manager import StrValueManager
20+
from app.translator.platforms.falco.escape_manager import FalcoRuleEscapeManager, falco_rule_escape_manager
21+
22+
23+
class FalcoRuleStrValueManager(StrValueManager):
24+
escape_manager: FalcoRuleEscapeManager = falco_rule_escape_manager
25+
26+
27+
falco_rule_str_value_manager = FalcoRuleStrValueManager()

0 commit comments

Comments
 (0)