GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 73c5c0...bade8b )
by Drew J.
43s
created

AWSConfigRule.evaluate_compliance()   B

Complexity

Conditions 3

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 3
c 4
b 0
f 0
dl 0
loc 28
rs 8.8571
1
import abc
2
import json, boto3
3
import botocore.exceptions
4
5
import backoff
6
7
from awslambdahelper.evaluation import AWSConfigEvaluation
8
9
MAX_BACKOFF_TRIES = 100
10
11
class AWSConfigRule(object):
12
    """
13
    Defines the business logic for processing either scheduled or config change AWS Config rules
14
    """
15
    #: Specifies an AWS Config Rule which is triggered by a resource configuration
16
    CALL_TYPE_CONFIGURATION_CHANGE = 'ConfigurationItemChangeNotification'
17
    #: Specifies an AWS Config Rule which is triggered on a scheduled basis
18
    CALL_TYPE_SCHEDULED = 'ScheduledNotification'
19
    #: List of resources which this rule can evaluate. Only application for ConfigurationChange rules.
20
    APPLICABLE_RESOURCES = []
21
22
    @classmethod
23
    def handler(cls, event, context):
24
        """
25
        Allow a single entrypoint without extra boilerplate code.
26
27
        >>> from awslambdahelper import AWSConfigRule,InsufficientDataEvaluation
28
        >>> class MyAwesomeRule(AWSConfigRule):
29
        ...     APPLICABLE_RESOURCES = ["AWS::EC2::Instance"]
30
        ...     def find_violation_config_change(self, rule_parameters, config):
31
        ...         return [InsufficientDataEvaluation()]
32
        >>>
33
        >>> # The entrypoint for lambda would be set as "file_name.MyAwesomeRule.handler"
34
35
        :param event: See `Event Attributes
36
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_example-events.html#w2ab1c13c33c27c15c15>`_
37
            in the AWS Config Developer guide.
38
        :type event: dict
39
        :param context: See `Context Object <http://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html#python-context-object-methods>`_
40
        :type context: dict
41
        :return:
42
        """
43
        rule = cls(cls.APPLICABLE_RESOURCES)
44
        rule.lambda_handler(event, context)
45
46
    def __init__(self, applicable_resources=None):
47
        """
48
        If this rule is for handling ConfigurationChange events, then the "Applicable Resources" attribute must be set.
49
        If this is for handling Scheduled events, then no item is required.
50
51
        :param applicable_resources: A list of AWS resources which this rule evaluates. Only applicable for
52
            Configuration Change rules, and not Scheduled rules. See `Evaluating Additional Resource Types
53
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_nodejs.html#creating-custom-rules-for-additional-resource-types>`_,
54
            and
55
            `Supported AWS Resource Types <http://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources>`_.
56
        :type applicable_resources: Union[List,Tuple]
57
        """
58
        if applicable_resources is None:
59
            self.applicable_resources = self.APPLICABLE_RESOURCES
60
        else:
61
            self.applicable_resources = applicable_resources
62
        self.call_type = None
63
64
    @property
65
    def is_config_change_call(self):
66
        return self.call_type == self.CALL_TYPE_CONFIGURATION_CHANGE
67
68
    @property
69
    def is_scheduled_call(self):
70
        return self.call_type == self.CALL_TYPE_SCHEDULED
71
72
    @staticmethod
73
    def put_evaluations(*args, **kwargs):
74
        return boto3.client("config").put_evaluations(
75
            *args, **kwargs
76
        )
77
78
    def lambda_handler(self, event, context):
79
        """
80
        .. deprecated:: 1.1.4
81
            Use :py:meth:`~awslambdahelper.AWSConfigRule.handler`
82
        """
83
        invoking_event = json.loads(event["invokingEvent"])
84
        if 'ruleParameters' in event:
85
            rule_parameters = json.loads(event["ruleParameters"])
86
        else:
87
            rule_parameters = {}
88
89
        self.call_type = invoking_event['messageType']
90
91
        result_token = "No token found."
92
        if "resultToken" in event:
93
            result_token = event["resultToken"]
94
95
        evaluations = []
96
97
        if self.is_config_change_call:
98
99
            configuration_item = invoking_event["configurationItem"]
100
            evaluation_responses = self.evaluate_compliance(
101
                config=configuration_item,
102
                rule_parameters=rule_parameters,
103
                event=event
104
            )
105
106
            for evaluation_response in evaluation_responses:
107
                evaluation = evaluation_response.set(
108
                    ResourceType=configuration_item["resourceType"],
109
                    ResourceId=configuration_item["resourceId"],
110
                    OrderingTimestamp=configuration_item["configurationItemCaptureTime"]
111
                ).to_dict()
112
                evaluations.append(evaluation)
113
        else:
114
            evaluation_responses = self.evaluate_compliance(
115
                rule_parameters=rule_parameters,
116
                event=event
117
            )
118
119
            for evaluation_response in evaluation_responses:
120
                evaluations.append(evaluation_response.set(
121
                    OrderingTimestamp=invoking_event["notificationCreationTime"]
122
                ).to_dict())
123
124
        chunk_size = 100
125
        for evaluation_chunk in range(0, len(evaluations), chunk_size):
126
            self.put_evaluations(
127
                Evaluations=evaluations[evaluation_chunk:evaluation_chunk + chunk_size],
128
                ResultToken=result_token
129
            )
130
131
    def evaluate_compliance(self, rule_parameters, event, config=None):
132
        """
133
        A facade to delegate the event to either the :py:meth:`~awslambdahelper.AWSConfigRule.find_violation_config_change`, or
134
        :py:meth:`~awslambdahelper.AWSConfigRule.find_violation_scheduled`.
135
136
        :param rule_parameters: A list of key/pairs which are to be provided to the rule.
137
        :type: dict
138
        :param event:
139
        :param config:
140
        :return:
141
        """
142
        if self.is_config_change_call:
143
            if config["resourceType"] not in self.applicable_resources:
144
                return [NotApplicableEvaluation(
145
                    ResourceType=config["resourceType"],
146
                )]
147
148
            violations = self.find_violation_config_change(
149
                rule_parameters=rule_parameters,
150
                config=config
151
            )
152
        else:
153
            violations = self.find_violation_scheduled(
154
                rule_parameters=rule_parameters,
155
                accountid=event['accountId']
156
            )
157
158
        return violations
159
160
    @backoff.on_exception(backoff.expo,
161
                          botocore.exceptions.ClientError,
162
                          max_tries=MAX_BACKOFF_TRIES,
163
                          jitter=backoff.full_jitter)
164
    def _aws_call(self, callable):
165
        """
166
        Wrapper to ease testing.
167
        Decorators make mocking functions that just little bit harder. For this reason, pass
168
        a callable into this method which can handle our AWS calls.
169
170
        :param callable:
171
        :return:
172
        """
173
        return callable()
174
175
    def find_violation_config_change(self, rule_parameters, config):
176
        """
177
        Place holder function for configuration change rules. Needs to be overriden by super class.
178
179
        :raises: NotImplementedError
180
        :param rule_parameters:
181
        :param config:
182
        :return: None
183
        """
184
        raise NotImplementedError(type(self).__name__ + ":find_violation_config_change() is not implemented.")
185
186
    def find_violation_scheduled(self, rule_parameters, accountid):
187
        """
188
        Place holder function for configuration change rules. Needs to be overriden by super class.
189
190
        :param rule_parameters:
191
        :param accountid:
192
        :return: None
193
        """
194
        raise NotImplementedError(type(self).__name__ + ":find_violation_scheduled() is not implemented.")
195
196
197
class CompliantEvaluation(AWSConfigEvaluation):
198
    """
199
    A rule is compliant if all of the resources that the rule evaluates comply with it,
200
    """
201
202
    def __init__(self, Annotation="This resource is compliant with the rule.", ResourceType=None,
203
                 ResourceId=None,
204
                 OrderingTimestamp=None):
205
        """
206
        :param Annotation: An explanation to attach to the evaluation result. Shown in the AWS Config Console.
207
        :type Annotation: str
208
        :param ResourceType:  A list of AWS resources which this rule evaluates. See `Evaluating Additional Resource Types
209
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_nodejs.html#creating-custom-rules-for-additional-resource-types>`_,
210
            and
211
            `Supported AWS Resource Types <http://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources>`_.
212
        :type ResourceType: str
213
        :param ResourceId: The id (eg, id-000000) or the ARN (eg, arn:aws:iam:01234567890:eu-west-1:..) for the resource
214
        :param OrderingTimestamp: The time of the event in AWS Config that triggered the evaluation.
215
        """
216
        super(CompliantEvaluation, self).__init__(
217
            AWSConfigEvaluation.TYPE_COMPLIANT,
218
            Annotation,
219
            ResourceType=ResourceType,
220
            ResourceId=ResourceId,
221
            OrderingTimestamp=OrderingTimestamp,
222
        )
223
224
225
class NonCompliantEvaluation(AWSConfigEvaluation):
226
    """
227
    A rule is noncompliant if any of these resources do not comply.
228
    """
229
230
    def __init__(self, Annotation, ResourceType=None, ResourceId=None,
231
                 OrderingTimestamp=None):
232
        """
233
        :param Annotation: An explanation to attach to the evaluation result. Shown in the AWS Config Console.
234
        :type Annotation: str
235
        :param ResourceType:  A list of AWS resources which this rule evaluates. See `Evaluating Additional Resource Types
236
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_nodejs.html#creating-custom-rules-for-additional-resource-types>`_,
237
            and
238
            `Supported AWS Resource Types <http://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources>`_.
239
        :type ResourceType: str
240
        :param ResourceId: The id (eg, id-000000) or the ARN (eg, arn:aws:iam:01234567890:eu-west-1:..) for the resource
241
        :param OrderingTimestamp: The time of the event in AWS Config that triggered the evaluation.
242
        """
243
        super(NonCompliantEvaluation, self).__init__(
244
            AWSConfigEvaluation.TYPE_NON_COMPLIANT,
245
            Annotation,
246
            ResourceType=ResourceType,
247
            ResourceId=ResourceId,
248
            OrderingTimestamp=OrderingTimestamp
249
        )
250
251
252
class NotApplicableEvaluation(AWSConfigEvaluation):
253
    """
254
    This resource is not applicable for this rule.
255
    """
256
257
    def __init__(self, ResourceType, ResourceId=None,
258
                 OrderingTimestamp=None):
259
        """
260
        :param ResourceType:  A list of AWS resources which this rule evaluates. See `Evaluating Additional Resource Types
261
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_nodejs.html#creating-custom-rules-for-additional-resource-types>`_,
262
            and
263
            `Supported AWS Resource Types <http://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources>`_.
264
        :type ResourceType: str
265
        :param ResourceId: The id (eg, id-000000) or the ARN (eg, arn:aws:iam:01234567890:eu-west-1:..) for the resource
266
        :param OrderingTimestamp: The time of the event in AWS Config that triggered the evaluation.
267
        """
268
        super(NotApplicableEvaluation, self).__init__(
269
            AWSConfigEvaluation.TYPE_NOT_APPLICABLE,
270
            "The rule doesn't apply to resources of type " + ResourceType + ".",
271
            ResourceType=ResourceType,
272
            ResourceId=ResourceId,
273
            OrderingTimestamp=OrderingTimestamp
274
        )
275
276
277
class InsufficientDataEvaluation(AWSConfigEvaluation):
278
    """
279
    AWS Config returns the INSUFFICIENT_DATA value when no evaluation results are available for the AWS resource or
280
    Config rule.
281
    """
282
283
    def __init__(self, Annotation, ResourceType=None, ResourceId=None,
284
                 OrderingTimestamp=None):
285
        """
286
        :param Annotation: An explanation to attach to the evaluation result. Shown in the AWS Config Console.
287
        :type Annotation: str
288
        :param ResourceType:  A list of AWS resources which this rule evaluates. See `Evaluating Additional Resource Types
289
            <http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_nodejs.html#creating-custom-rules-for-additional-resource-types>`_,
290
            and
291
            `Supported AWS Resource Types <http://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html#supported-resources>`_.
292
        :type ResourceType: str
293
        :param ResourceId: The id (eg, id-000000) or the ARN (eg, arn:aws:iam:01234567890:eu-west-1:..) for the resource
294
        :type ResourceId: str
295
        :param OrderingTimestamp: The time of the event in AWS Config that triggered the evaluation.
296
        """
297
        super(InsufficientDataEvaluation, self).__init__(
298
            AWSConfigEvaluation.TYPE_INSUFFICIENT_DATA,
299
            Annotation,
300
            ResourceType=ResourceType,
301
            ResourceId=ResourceId,
302
            OrderingTimestamp=OrderingTimestamp
303
        )
304