Skip to content

Commit d51d2bb

Browse files
committed
add periodic rule support
1 parent 178d423 commit d51d2bb

File tree

2 files changed

+103
-16
lines changed

2 files changed

+103
-16
lines changed

functions/custom_config_rule.py

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,29 +102,113 @@ def build_evaluation(configuration_item, event, rule_parameters):
102102
}
103103

104104

105+
def evaluate_parameters(rule_parameters):
106+
if "applicableResourceType" not in rule_parameters:
107+
raise ValueError(
108+
'The parameter with "applicableResourceType" as key must be defined.'
109+
)
110+
if not rule_parameters["applicableResourceType"]:
111+
raise ValueError(
112+
'The parameter "applicableResourceType" must have a defined value.'
113+
)
114+
return rule_parameters
115+
116+
117+
def get_configuration_items(resource_type):
118+
resource_keys = list_discovered_resources(resource_type)
119+
resource_configs = batch_get_resource_config(resource_keys)
120+
configuration_items = []
121+
for rc in resource_configs:
122+
configuration_items.append(
123+
get_configuration(
124+
rc["resourceType"],
125+
rc["resourceId"],
126+
)
127+
)
128+
return configuration_items
129+
130+
131+
def list_discovered_resources(resource_type):
132+
response = AWS_CONFIG_CLIENT.list_discovered_resources(resourceType=resource_type)
133+
resources = [
134+
{"resourceType": r["resourceType"], "resourceId": r["resourceId"]}
135+
for r in response["resourceIdentifiers"]
136+
]
137+
while "nextToken" in response:
138+
response = AWS_CONFIG_CLIENT.list_discovered_resources(
139+
resourceType=resource_type, nextToken=response["nextToken"]
140+
)
141+
resources.extend(
142+
[
143+
{"resourceType": r["resourceType"], "resourceId": r["resourceId"]}
144+
for r in response["resourceIdentifiers"]
145+
]
146+
)
147+
return resources
148+
149+
150+
def batch_get_resource_config(resource_keys):
151+
if len(resource_keys) == 0:
152+
return []
153+
response = AWS_CONFIG_CLIENT.batch_get_resource_config(resourceKeys=resource_keys)
154+
resources = [
155+
{
156+
"resourceType": r["resourceType"],
157+
"resourceId": r["resourceId"],
158+
"configurationItemCaptureTime": r["configurationItemCaptureTime"],
159+
}
160+
for r in response["baseConfigurationItems"]
161+
]
162+
while len(response["unprocessedResourceKeys"]) > 0:
163+
response = AWS_CONFIG_CLIENT.batch_get_resource_config(
164+
resourceKeys=response["unprocessedResourceKeys"]
165+
)
166+
resources.extend(
167+
[
168+
{
169+
"resourceType": r["resourceType"],
170+
"resourceId": r["resourceId"],
171+
"configurationItemCaptureTime": r["configurationItemCaptureTime"],
172+
}
173+
for r in response["baseConfigurationItems"]
174+
]
175+
)
176+
return resources
177+
178+
105179
def lambda_handler(event, context):
106180
# pylint: disable=unused-argument
107181
check_defined(event, "event")
108182
invoking_event = json.loads(event["invokingEvent"])
109183
rule_parameters = (
110184
json.loads(event["ruleParameters"]) if "ruleParameters" in event else {}
111185
)
112-
if invoking_event["messageType"] in [
113-
"ConfigurationItemChangeNotification",
114-
"OversizedConfigurationItemChangeNotification",
115-
]:
116-
configuration_item = get_configuration_item(invoking_event)
117-
evaluations = [
118-
build_evaluation(
119-
configuration_item,
120-
event,
121-
rule_parameters,
122-
),
123-
]
124-
else:
125-
return build_internal_error_response(
126-
"Unexpected message type", str(invoking_event)
127-
)
186+
match invoking_event["messageType"]:
187+
case "ScheduledNotification":
188+
valid_rule_parameters = evaluate_parameters(rule_parameters)
189+
evaluations = [
190+
build_evaluation(
191+
configuration_item,
192+
event,
193+
valid_rule_parameters,
194+
)
195+
for configuration_item in get_configuration_items(
196+
valid_rule_parameters["applicableResourceType"]
197+
)
198+
]
199+
case "ConfigurationItemChangeNotification" | "OversizedConfigurationItemChangeNotification":
200+
configuration_item = get_configuration_item(invoking_event)
201+
evaluations = [
202+
build_evaluation(
203+
configuration_item,
204+
event,
205+
rule_parameters,
206+
),
207+
]
208+
case _:
209+
return build_internal_error_response(
210+
"Unexpected message type", str(invoking_event)
211+
)
128212
AWS_CONFIG_CLIENT.put_evaluations(
129213
Evaluations=evaluations,
130214
ResultToken=event["resultToken"],

rules/_sample/resources.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Resources:
1010
SourceDetails:
1111
- EventSource: aws.config
1212
MessageType: ConfigurationItemChangeNotification
13+
- EventSource: aws.config
14+
MessageType: ScheduledNotification
15+
MaximumExecutionFrequency: One_Hour
1316
InputParameters:
1417
"{parameterName}": "{parameterValue}"
1518
Remediation:

0 commit comments

Comments
 (0)