Skip to content

Commit 049c747

Browse files
Merge pull request #78 from jinyoungmoonDEV/master
fix: Security Group Rule에 rule_id 정보 추가
2 parents 59c8046 + 51eee05 commit 049c747

File tree

4 files changed

+152
-51
lines changed

4 files changed

+152
-51
lines changed

src/plugin/conf/cloud_service_conf.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,24 +328,24 @@
328328
"tags": {
329329
"latitude": "3.1390",
330330
"longitude": "101.6869",
331-
"continent": "asia_pacific"
332-
}
331+
"continent": "asia_pacific",
332+
},
333333
},
334334
"mx-central-1": {
335335
"name": "Mexico (Central)",
336336
"tags": {
337337
"latitude": "20.5888",
338338
"longitude": "-100.3899",
339-
"continent": "north_america"
340-
}
339+
"continent": "north_america",
340+
},
341341
},
342342
"ap-southeast-6": {
343343
"name": "Asia Pacific (Thailand)",
344344
"tags": {
345345
"latitude": "13.7563",
346346
"longitude": "100.5018",
347-
"continent": "asia_pacific"
348-
}
347+
"continent": "asia_pacific",
348+
},
349349
},
350350
"global": {"name": "Global"},
351351
}

src/plugin/connector/ec2/security_group_connector.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ def get_security_groups(self):
2323
)
2424
return response_iterator
2525

26+
def get_security_group_rules(self):
27+
paginator = self.client.get_paginator("describe_security_group_rules")
28+
response_iterator = paginator.paginate(
29+
PaginationConfig={
30+
"MaxItems": 10000,
31+
"PageSize": 50,
32+
}
33+
)
34+
return response_iterator
35+
2636
def get_filtered_instances(self, filters):
2737
paginator = self.client.get_paginator("describe_instances")
2838
response_iterator = paginator.paginate(

src/plugin/manager/ec2/security_group_manager.py

Lines changed: 134 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import copy
22
from spaceone.inventory.plugin.collector.lib import *
33
from ..base import ResourceManager
4-
from ...conf.cloud_service_conf import ASSET_URL, INSTANCE_FILTERS, DEFAULT_VULNERABLE_PORTS
4+
from ...conf.cloud_service_conf import (
5+
ASSET_URL,
6+
INSTANCE_FILTERS,
7+
DEFAULT_VULNERABLE_PORTS,
8+
)
59
from plugin.error.custom import ERROR_VULNERABLE_PORTS
610

711

@@ -16,6 +20,7 @@ def __init__(self, *args, **kwargs):
1620
self.cloud_service_type = "SecurityGroup"
1721
self.metadata_path = "metadata/ec2/sg.yaml"
1822
self.include_vpc_default = False
23+
self.sg_rules_for_this_group = []
1924

2025
def create_cloud_service_type(self):
2126
result = []
@@ -50,9 +55,23 @@ def create_cloud_service(self, region, options, secret_data, schema):
5055
account_id = options.get("account_id", "")
5156
self.connector.load_account_id(account_id)
5257

58+
# Get Security Group Rules Detail
59+
sg_rules_detail = self.connector.get_security_group_rules()
60+
61+
sg_rules_map = {}
62+
for data in sg_rules_detail:
63+
for rule in data.get("SecurityGroupRules", []):
64+
group_id = rule.get("GroupId")
65+
if group_id not in sg_rules_map:
66+
sg_rules_map[group_id] = []
67+
sg_rules_map[group_id].append(rule)
68+
5369
for data in results:
5470
for raw in data.get("SecurityGroups", []):
5571
try:
72+
group_id = raw.get("GroupId", "")
73+
self.sg_rules_for_this_group = sg_rules_map.get(group_id, [])
74+
5675
if (
5776
self.include_vpc_default is False
5877
and raw.get("VpcId") in default_vpcs
@@ -62,75 +81,94 @@ def create_cloud_service(self, region, options, secret_data, schema):
6281
# Inbound Rules
6382
inbound_rules = []
6483
for in_rule in raw.get("IpPermissions", []):
84+
in_rule_copy = copy.deepcopy(in_rule)
85+
6586
for _ip_range in in_rule.get("IpRanges", []):
66-
in_rule_copy = copy.deepcopy(in_rule)
6787
inbound_rules.append(
68-
self.custom_security_group_inbound_rule_info(
69-
in_rule_copy, _ip_range, "ip_ranges",vulnerable_ports
88+
self._custom_security_group_inbound_rule_info(
89+
raw_rule=in_rule_copy,
90+
remote=_ip_range,
91+
remote_type="ip_ranges",
92+
is_egress=False,
93+
vulnerable_ports=vulnerable_ports,
7094
)
7195
)
7296

7397
for _user_group_pair in in_rule.get("UserIdGroupPairs", []):
74-
in_rule_copy = copy.deepcopy(in_rule)
7598
inbound_rules.append(
76-
self.custom_security_group_inbound_rule_info(
77-
in_rule_copy,
78-
_user_group_pair,
79-
"user_id_group_pairs",
80-
vulnerable_ports,
99+
self._custom_security_group_inbound_rule_info(
100+
raw_rule=in_rule_copy,
101+
remote=_user_group_pair,
102+
remote_type="user_id_group_pairs",
103+
is_egress=False,
104+
vulnerable_ports=vulnerable_ports,
81105
)
82106
)
83107

84108
for _ip_v6_range in in_rule.get("Ipv6Ranges", []):
85-
in_rule_copy = copy.deepcopy(in_rule)
86109
inbound_rules.append(
87-
self.custom_security_group_inbound_rule_info(
88-
in_rule_copy, _ip_v6_range, "ipv6_ranges",vulnerable_ports
110+
self._custom_security_group_inbound_rule_info(
111+
raw_rule=in_rule_copy,
112+
remote=_ip_v6_range,
113+
remote_type="ipv6_ranges",
114+
is_egress=False,
115+
vulnerable_ports=vulnerable_ports,
89116
)
90117
)
91118

92119
for prefix_list_id in in_rule.get("PrefixListIds", []):
93-
in_rule_copy = copy.deepcopy(in_rule)
94120
inbound_rules.append(
95-
self.custom_security_group_inbound_rule_info(
96-
in_rule_copy, prefix_list_id, "prefix_list_ids",vulnerable_ports
121+
self._custom_security_group_inbound_rule_info(
122+
raw_rule=in_rule_copy,
123+
remote=prefix_list_id,
124+
remote_type="prefix_list_ids",
125+
is_egress=False,
126+
vulnerable_ports=vulnerable_ports,
97127
)
98128
)
99129

100130
# Outbound Rules
101131
outbound_rules = []
102132
for out_rule in raw.get("IpPermissionsEgress", []):
133+
out_rule_copy = copy.deepcopy(out_rule)
134+
103135
for _ip_range in out_rule.get("IpRanges", []):
104-
out_rule_copy = copy.deepcopy(out_rule)
105136
outbound_rules.append(
106-
self.custom_security_group_rule_info(
107-
out_rule_copy, _ip_range, "ip_ranges"
137+
self._custom_security_group_inbound_rule_info(
138+
raw_rule=out_rule_copy,
139+
remote=_ip_range,
140+
remote_type="ip_ranges",
141+
is_egress=True,
108142
)
109143
)
110144

111145
for _user_group_pairs in out_rule.get("UserIdGroupPairs", []):
112-
out_rule_copy = copy.deepcopy(out_rule)
113146
outbound_rules.append(
114-
self.custom_security_group_rule_info(
115-
out_rule_copy,
116-
_user_group_pairs,
117-
"user_id_group_pairs",
147+
self._custom_security_group_inbound_rule_info(
148+
raw_rule=out_rule_copy,
149+
remote=_user_group_pairs,
150+
remote_type="user_id_group_pairs",
151+
is_egress=True,
118152
)
119153
)
120154

121155
for _ip_v6_range in out_rule.get("Ipv6Ranges", []):
122-
out_rule_copy = copy.deepcopy(out_rule)
123156
outbound_rules.append(
124-
self.custom_security_group_rule_info(
125-
out_rule_copy, _ip_v6_range, "ipv6_ranges"
157+
self._custom_security_group_inbound_rule_info(
158+
raw_rule=out_rule_copy,
159+
remote=_ip_v6_range,
160+
remote_type="ipv6_ranges",
161+
is_egress=True,
126162
)
127163
)
128164

129165
for prefix_list_id in out_rule.get("PrefixListIds", []):
130-
out_rule_copy = copy.deepcopy(out_rule)
131166
outbound_rules.append(
132-
self.custom_security_group_rule_info(
133-
out_rule_copy, prefix_list_id, "prefix_list_ids"
167+
self._custom_security_group_inbound_rule_info(
168+
raw_rule=out_rule_copy,
169+
remote=prefix_list_id,
170+
remote_type="prefix_list_ids",
171+
is_egress=True,
134172
)
135173
)
136174

@@ -151,7 +189,6 @@ def create_cloud_service(self, region, options, secret_data, schema):
151189
)
152190
sg_vo = raw
153191

154-
group_id = sg_vo.get("GroupId", "")
155192
link = f"https://console.aws.amazon.com/ec2/v2/home?region={region}#SecurityGroups:group-id={group_id}"
156193
reference = self.get_reference(group_id, link)
157194

@@ -167,15 +204,7 @@ def create_cloud_service(self, region, options, secret_data, schema):
167204
reference=reference,
168205
)
169206
yield cloud_service
170-
# yield {
171-
# "data": sg_vo,
172-
# "name": sg_vo.group_name,
173-
# "account": self.account_id,
174-
# "tags": self.convert_tags_to_dict_type(raw.get("Tags", [])),
175-
# }
176-
177207
except Exception as e:
178-
# resource_id = raw.get("GroupId", "")
179208
yield make_error_response(
180209
error=e,
181210
provider=self.provider,
@@ -184,24 +213,82 @@ def create_cloud_service(self, region, options, secret_data, schema):
184213
region_name=region,
185214
)
186215

187-
def custom_security_group_inbound_rule_info(self, raw_rule, remote, remote_type, vulnerable_ports):
188-
raw_rule = self.custom_security_group_rule_info(raw_rule, remote, remote_type)
216+
@staticmethod
217+
def _get_matched_security_group_rule_id(
218+
raw_rule, sg_rules_detail, remote, remote_type, is_egress
219+
):
220+
raw_protocol = raw_rule.get("IpProtocol")
221+
raw_from_port = raw_rule.get("FromPort")
222+
raw_to_port = raw_rule.get("ToPort")
223+
224+
for sg_rule in sg_rules_detail:
225+
if sg_rule.get("IsEgress") != is_egress:
226+
continue
227+
228+
if sg_rule.get("IpProtocol") != raw_protocol:
229+
continue
230+
231+
if raw_from_port:
232+
sg_from_port = sg_rule.get("FromPort")
233+
if raw_from_port is not None and sg_from_port is not None:
234+
if raw_from_port != sg_from_port:
235+
continue
236+
237+
if raw_to_port:
238+
sg_to_port = sg_rule.get("ToPort")
239+
if raw_to_port is not None and sg_to_port is not None:
240+
if raw_to_port != sg_to_port:
241+
continue
242+
243+
if remote_type == "ip_ranges":
244+
if sg_rule.get("CidrIpv4") != remote.get("CidrIp"):
245+
continue
246+
elif remote_type == "ipv6_ranges":
247+
if sg_rule.get("CidrIpv6") != remote.get("CidrIpv6"):
248+
continue
249+
elif remote_type == "prefix_list_ids":
250+
if sg_rule.get("PrefixListId") != remote.get("PrefixListId"):
251+
continue
252+
elif remote_type == "user_id_group_pairs":
253+
referenced_group = sg_rule.get("ReferencedGroupInfo", {})
254+
if referenced_group.get("GroupId") != remote.get("GroupId"):
255+
continue
256+
257+
return sg_rule.get("SecurityGroupRuleId")
258+
259+
return None
260+
261+
def _custom_security_group_inbound_rule_info(
262+
self, raw_rule, remote, remote_type, is_egress, vulnerable_ports=None
263+
):
264+
rule_id = self._get_matched_security_group_rule_id(
265+
raw_rule=raw_rule,
266+
sg_rules_detail=self.sg_rules_for_this_group,
267+
remote=remote,
268+
remote_type=remote_type,
269+
is_egress=is_egress,
270+
)
271+
272+
raw_rule = self._custom_security_group_rule_info(raw_rule, remote, remote_type)
189273

190274
protocol_display = raw_rule.get("protocol_display")
191275

192276
if vulnerable_ports:
193-
ports = self._get_vulnerable_ports(protocol_display, raw_rule, vulnerable_ports)
277+
ports = self._get_vulnerable_ports(
278+
protocol_display, raw_rule, vulnerable_ports
279+
)
194280

195281
raw_rule.update(
196282
{
283+
"rule_id": rule_id,
197284
"vulnerable_ports": ports,
198-
"detected_vulnerable_ports": True if ports else False
285+
"detected_vulnerable_ports": True if ports else False,
199286
}
200287
)
201288

202289
return raw_rule
203290

204-
def custom_security_group_rule_info(self, raw_rule, remote, remote_type):
291+
def _custom_security_group_rule_info(self, raw_rule, remote, remote_type):
205292
protocol_display = self._get_protocol_display(raw_rule.get("IpProtocol"))
206293
raw_rule.update(
207294
{
@@ -331,7 +418,9 @@ def get_instance_name_from_tags(instance):
331418
return ""
332419

333420
@staticmethod
334-
def _get_vulnerable_ports(protocol_display: str, raw_rule: dict, vulnerable_ports: str):
421+
def _get_vulnerable_ports(
422+
protocol_display: str, raw_rule: dict, vulnerable_ports: str
423+
):
335424
try:
336425
ports = []
337426

src/plugin/metadata/ec2/sg.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ tabs.1:
198198
type: table
199199
root_path: data.ip_permissions
200200
fields:
201+
- Rule ID: rule_id
201202
- Protocol: protocol_display
202203
type: enum
203204
enums:
@@ -215,6 +216,7 @@ tabs.2:
215216
type: table
216217
root_path: data.ip_permissions_egress
217218
fields:
219+
- Rule ID: rule_id
218220
- Protocol: protocol_display
219221
type: enum
220222
enums:

0 commit comments

Comments
 (0)