@liflig/cdk 1.51.0 → 1.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +1 -2
- package/lib/index.js +2 -4
- package/package.json +1 -3
- package/assets/cloudtrail-slack-integration-lambda/main.py +0 -249
- package/lib/cloudtrail-slack-integration/cloudtrail-slack-integration.d.ts +0 -43
- package/lib/cloudtrail-slack-integration/cloudtrail-slack-integration.js +0 -210
- package/lib/cloudtrail-slack-integration/index.d.ts +0 -1
- package/lib/cloudtrail-slack-integration/index.js +0 -6
package/lib/index.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ import * as webapp from "./webapp";
|
|
|
7
7
|
import * as configureParameters from "./configure-parameters";
|
|
8
8
|
import * as ecs from "./ecs";
|
|
9
9
|
import * as loadBalancer from "./load-balancer";
|
|
10
|
-
import * as cloudTrailSlackIntegration from "./cloudtrail-slack-integration";
|
|
11
10
|
import * as rds from "./rds";
|
|
12
11
|
import * as platform from "./platform";
|
|
13
12
|
export { BastionHost } from "./bastion-host";
|
|
@@ -21,7 +20,7 @@ export { SsmParameterBackedResource } from "./ssm-parameter-backed-resource";
|
|
|
21
20
|
export { SsmParameterReader } from "./ssm-parameter-reader";
|
|
22
21
|
export { tagResources } from "./tags";
|
|
23
22
|
export { WebappDeployViaRole } from "./webapp-deploy-via-role";
|
|
24
|
-
export { alarms, cdkPipelines, griid, pipelines, ses, webapp, configureParameters, ecs, loadBalancer, rds, platform,
|
|
23
|
+
export { alarms, cdkPipelines, griid, pipelines, ses, webapp, configureParameters, ecs, loadBalancer, rds, platform, };
|
|
25
24
|
/**
|
|
26
25
|
* Check if we are synthesizing a snapshot by setting IS_SNAPSHOT
|
|
27
26
|
* environment variable to true.
|
package/lib/index.js
CHANGED
|
@@ -10,7 +10,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
10
10
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.isSnapshot = exports.
|
|
13
|
+
exports.isSnapshot = exports.platform = exports.rds = exports.loadBalancer = exports.ecs = exports.configureParameters = exports.webapp = exports.ses = exports.pipelines = exports.griid = exports.cdkPipelines = exports.alarms = exports.WebappDeployViaRole = exports.tagResources = exports.SsmParameterReader = exports.SsmParameterBackedResource = exports.createCloudAssemblySnapshot = exports.HostedZoneWithParam = exports.CrossRegionSsmParameter = exports.BastionHost = void 0;
|
|
14
14
|
const alarms = require("./alarms");
|
|
15
15
|
exports.alarms = alarms;
|
|
16
16
|
const cdkPipelines = require("./cdk-pipelines");
|
|
@@ -29,8 +29,6 @@ const ecs = require("./ecs");
|
|
|
29
29
|
exports.ecs = ecs;
|
|
30
30
|
const loadBalancer = require("./load-balancer");
|
|
31
31
|
exports.loadBalancer = loadBalancer;
|
|
32
|
-
const cloudTrailSlackIntegration = require("./cloudtrail-slack-integration");
|
|
33
|
-
exports.cloudTrailSlackIntegration = cloudTrailSlackIntegration;
|
|
34
32
|
const rds = require("./rds");
|
|
35
33
|
exports.rds = rds;
|
|
36
34
|
const platform = require("./platform");
|
|
@@ -64,4 +62,4 @@ Object.defineProperty(exports, "WebappDeployViaRole", { enumerable: true, get: f
|
|
|
64
62
|
* happen during snapshot creation.
|
|
65
63
|
*/
|
|
66
64
|
exports.isSnapshot = process.env.IS_SNAPSHOT === "true";
|
|
67
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQUFBLG1DQUFrQztBQTRCaEMsd0JBQU07QUEzQlIsZ0RBQStDO0FBNEI3QyxvQ0FBWTtBQTNCZCxpQ0FBZ0M7QUE0QjlCLHNCQUFLO0FBM0JQLHlDQUF3QztBQTRCdEMsOEJBQVM7QUEzQlgsNkJBQTRCO0FBNEIxQixrQkFBRztBQTNCTCxtQ0FBa0M7QUE0QmhDLHdCQUFNO0FBM0JSLDhEQUE2RDtBQTRCM0Qsa0RBQW1CO0FBM0JyQiw2QkFBNEI7QUE0QjFCLGtCQUFHO0FBM0JMLGdEQUErQztBQTRCN0Msb0NBQVk7QUEzQmQsNkJBQTRCO0FBNEIxQixrQkFBRztBQTNCTCx1Q0FBc0M7QUE0QnBDLDRCQUFRO0FBMUJWLGdFQUFnRTtBQUNoRSx1Q0FBdUM7QUFFdkMsK0NBQTRDO0FBQW5DLDJHQUFBLFdBQVcsT0FBQTtBQUNwQixvREFBaUM7QUFDakMsK0NBQTRCO0FBQzVCLDJFQUFzRTtBQUE3RCxxSUFBQSx1QkFBdUIsT0FBQTtBQUNoQyxxREFBa0M7QUFDbEMsbUVBQThEO0FBQXJELDZIQUFBLG1CQUFtQixPQUFBO0FBQzVCLHlDQUF5RDtBQUFoRCx3SEFBQSwyQkFBMkIsT0FBQTtBQUNwQyxpRkFBNEU7QUFBbkUsMklBQUEsMEJBQTBCLE9BQUE7QUFDbkMsK0RBQTJEO0FBQWxELDBIQUFBLGtCQUFrQixPQUFBO0FBQzNCLCtCQUFxQztBQUE1QixvR0FBQSxZQUFZLE9BQUE7QUFDckIsbUVBQThEO0FBQXJELDZIQUFBLG1CQUFtQixPQUFBO0FBZ0I1Qjs7Ozs7O0dBTUc7QUFDVSxRQUFBLFVBQVUsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsS0FBSyxNQUFNLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBhbGFybXMgZnJvbSBcIi4vYWxhcm1zXCJcbmltcG9ydCAqIGFzIGNka1BpcGVsaW5lcyBmcm9tIFwiLi9jZGstcGlwZWxpbmVzXCJcbmltcG9ydCAqIGFzIGdyaWlkIGZyb20gXCIuL2dyaWlkXCJcbmltcG9ydCAqIGFzIHBpcGVsaW5lcyBmcm9tIFwiLi9waXBlbGluZXNcIlxuaW1wb3J0ICogYXMgc2VzIGZyb20gXCIuL3Nlc1wiXG5pbXBvcnQgKiBhcyB3ZWJhcHAgZnJvbSBcIi4vd2ViYXBwXCJcbmltcG9ydCAqIGFzIGNvbmZpZ3VyZVBhcmFtZXRlcnMgZnJvbSBcIi4vY29uZmlndXJlLXBhcmFtZXRlcnNcIlxuaW1wb3J0ICogYXMgZWNzIGZyb20gXCIuL2Vjc1wiXG5pbXBvcnQgKiBhcyBsb2FkQmFsYW5jZXIgZnJvbSBcIi4vbG9hZC1iYWxhbmNlclwiXG5pbXBvcnQgKiBhcyByZHMgZnJvbSBcIi4vcmRzXCJcbmltcG9ydCAqIGFzIHBsYXRmb3JtIGZyb20gXCIuL3BsYXRmb3JtXCJcblxuLy8gVE9ETzogV2Ugd2FudCB0byBzd2l0Y2ggZXhwb3J0cyBzbyB0aGV5IGV2ZXJ5IGNvbnN0cnVjdCB1bmRlclxuLy8gIGEgbmFtZXNwYWNlIHN1Y2ggYXMgdGhlIHNucyBleHBvcnQuXG5cbmV4cG9ydCB7IEJhc3Rpb25Ib3N0IH0gZnJvbSBcIi4vYmFzdGlvbi1ob3N0XCJcbmV4cG9ydCAqIGZyb20gXCIuL2J1aWxkLWFydGlmYWN0c1wiXG5leHBvcnQgKiBmcm9tIFwiLi9jZGstZGVwbG95XCJcbmV4cG9ydCB7IENyb3NzUmVnaW9uU3NtUGFyYW1ldGVyIH0gZnJvbSBcIi4vY3Jvc3MtcmVnaW9uLXNzbS1wYXJhbWV0ZXJcIlxuZXhwb3J0ICogZnJvbSBcIi4vZWNzLXVwZGF0ZS1pbWFnZVwiXG5leHBvcnQgeyBIb3N0ZWRab25lV2l0aFBhcmFtIH0gZnJvbSBcIi4vaG9zdGVkLXpvbmUtd2l0aC1wYXJhbVwiXG5leHBvcnQgeyBjcmVhdGVDbG91ZEFzc2VtYmx5U25hcHNob3QgfSBmcm9tIFwiLi9zbmFwc2hvdHNcIlxuZXhwb3J0IHsgU3NtUGFyYW1ldGVyQmFja2VkUmVzb3VyY2UgfSBmcm9tIFwiLi9zc20tcGFyYW1ldGVyLWJhY2tlZC1yZXNvdXJjZVwiXG5leHBvcnQgeyBTc21QYXJhbWV0ZXJSZWFkZXIgfSBmcm9tIFwiLi9zc20tcGFyYW1ldGVyLXJlYWRlclwiXG5leHBvcnQgeyB0YWdSZXNvdXJjZXMgfSBmcm9tIFwiLi90YWdzXCJcbmV4cG9ydCB7IFdlYmFwcERlcGxveVZpYVJvbGUgfSBmcm9tIFwiLi93ZWJhcHAtZGVwbG95LXZpYS1yb2xlXCJcblxuZXhwb3J0IHtcbiAgYWxhcm1zLFxuICBjZGtQaXBlbGluZXMsXG4gIGdyaWlkLFxuICBwaXBlbGluZXMsXG4gIHNlcyxcbiAgd2ViYXBwLFxuICBjb25maWd1cmVQYXJhbWV0ZXJzLFxuICBlY3MsXG4gIGxvYWRCYWxhbmNlcixcbiAgcmRzLFxuICBwbGF0Zm9ybSxcbn1cblxuLyoqXG4gKiBDaGVjayBpZiB3ZSBhcmUgc3ludGhlc2l6aW5nIGEgc25hcHNob3QgYnkgc2V0dGluZyBJU19TTkFQU0hPVFxuICogZW52aXJvbm1lbnQgdmFyaWFibGUgdG8gdHJ1ZS5cbiAqXG4gKiBUaGlzIGFsbG93cyBmb3Igc3BlY2lhbCBjb25kaXRpb25hbCBsb2dpYyB0aGF0IHNob3VsZCBvbmx5XG4gKiBoYXBwZW4gZHVyaW5nIHNuYXBzaG90IGNyZWF0aW9uLlxuICovXG5leHBvcnQgY29uc3QgaXNTbmFwc2hvdCA9IHByb2Nlc3MuZW52LklTX1NOQVBTSE9UID09PSBcInRydWVcIlxuIl19
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liflig/cdk",
|
|
3
|
-
"version": "1.51.
|
|
3
|
+
"version": "1.51.1",
|
|
4
4
|
"description": "Experimental CDK library for Liflig",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
"@aws-cdk/aws-events-targets": "1.135.0",
|
|
48
48
|
"@aws-cdk/aws-iam": "1.135.0",
|
|
49
49
|
"@aws-cdk/aws-lambda": "1.135.0",
|
|
50
|
-
"@aws-cdk/aws-lambda-event-sources": "1.135.0",
|
|
51
50
|
"@aws-cdk/aws-logs": "1.135.0",
|
|
52
51
|
"@aws-cdk/aws-rds": "1.135.0",
|
|
53
52
|
"@aws-cdk/aws-route53": "1.135.0",
|
|
@@ -105,7 +104,6 @@
|
|
|
105
104
|
"@aws-cdk/aws-events-targets": "^1.108.1",
|
|
106
105
|
"@aws-cdk/aws-iam": "^1.108.1",
|
|
107
106
|
"@aws-cdk/aws-lambda": "^1.108.1",
|
|
108
|
-
"@aws-cdk/aws-lambda-event-sources": "^1.108.1",
|
|
109
107
|
"@aws-cdk/aws-logs": "^1.108.1",
|
|
110
108
|
"@aws-cdk/aws-rds": "^1.108.1",
|
|
111
109
|
"@aws-cdk/aws-route53": "^1.108.1",
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Transform CloudTrail events to payloads formatted for Slack's API, and send them
|
|
5
|
-
directly to Slack or through an SQS FIFO queue for deduplication.
|
|
6
|
-
|
|
7
|
-
The code below contains entrypoints for two Lambda functions (prefixed with `handler_`).
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import os
|
|
11
|
-
import logging
|
|
12
|
-
import json
|
|
13
|
-
import urllib.request
|
|
14
|
-
import boto3
|
|
15
|
-
|
|
16
|
-
logger = logging.getLogger()
|
|
17
|
-
logger.setLevel(logging.INFO)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def get_slack_payload_for_assume_role_event(event, account_friendly_names):
|
|
21
|
-
"""Parse a CloudTrail event related to the API call sts:AssumeRole,
|
|
22
|
-
and return a Slack-formatted attachment"""
|
|
23
|
-
event_account_id = event["account"]
|
|
24
|
-
event_detail = event["detail"]
|
|
25
|
-
request_parameters = event_detail.get("requestParameters", {}) or {}
|
|
26
|
-
|
|
27
|
-
timestamp = event_detail["eventTime"]
|
|
28
|
-
user_identity = event_detail["userIdentity"]
|
|
29
|
-
principal_id = user_identity["principalId"]
|
|
30
|
-
principal_account_id = user_identity["accountId"]
|
|
31
|
-
source_identity = request_parameters.get("sourceIdentity", "")
|
|
32
|
-
source_ip = event_detail.get("sourceIPAddress", "")
|
|
33
|
-
role_arn = request_parameters.get("roleArn", "")
|
|
34
|
-
|
|
35
|
-
fallback = f"Sensitive role accessed in '{event_account_id}'"
|
|
36
|
-
pretext_messages = [f":warning: Sensitive role in `{event_account_id}` assumed by"]
|
|
37
|
-
if principal_id.startswith("AIDA"):
|
|
38
|
-
pretext_messages.append("IAM user")
|
|
39
|
-
elif principal_id.startswith("AROA"):
|
|
40
|
-
pretext_messages.append("IAM role")
|
|
41
|
-
else:
|
|
42
|
-
pretext_messages.append("principal")
|
|
43
|
-
pretext_messages.append(f"in `{principal_account_id}`")
|
|
44
|
-
pretext = " ".join(pretext_messages)
|
|
45
|
-
|
|
46
|
-
text = [
|
|
47
|
-
f"*Role ARN:* `{role_arn}`",
|
|
48
|
-
f"*Principal Account ID:* `{principal_account_id}`",
|
|
49
|
-
f"*Principal ID:* `{principal_id}`",
|
|
50
|
-
f"*Source IP:* `{source_ip}`",
|
|
51
|
-
f"*Source Identity:* `{source_identity}`" if source_identity else "",
|
|
52
|
-
f"*Timestamp:* `{timestamp}`",
|
|
53
|
-
]
|
|
54
|
-
text = "\n".join(line for line in text if line)
|
|
55
|
-
for account_id, friendly_name in account_friendly_names.items():
|
|
56
|
-
pretext = pretext.replace(account_id, friendly_name)
|
|
57
|
-
fallback = fallback.replace(account_id, friendly_name)
|
|
58
|
-
return {
|
|
59
|
-
"attachments": [
|
|
60
|
-
{
|
|
61
|
-
"pretext": pretext,
|
|
62
|
-
"color": "warning",
|
|
63
|
-
"text": text,
|
|
64
|
-
"fallback": fallback,
|
|
65
|
-
"mrkdwn_in": ["pretext", "text"],
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def get_fallback_slack_payload_for_event(
|
|
72
|
-
event, account_friendly_names, fallback_parse_behavior=""
|
|
73
|
-
):
|
|
74
|
-
"""Parse a generic CloudTrail event related to an API call
|
|
75
|
-
and return a Slack-formatted attachment"""
|
|
76
|
-
event_account_id = event["account"]
|
|
77
|
-
event_detail = event["detail"]
|
|
78
|
-
event_name = event_detail["eventName"]
|
|
79
|
-
event_type = event_detail["eventType"]
|
|
80
|
-
event_time = event_detail["eventTime"]
|
|
81
|
-
pretext = f":warning: CloudTrail event in account `{event_account_id}`"
|
|
82
|
-
fallback = f"CloudTrail event in account '{event_account_id}'"
|
|
83
|
-
if fallback_parse_behavior == "DUMP_EVENT":
|
|
84
|
-
text = "\n".join(
|
|
85
|
-
["*Event:*", "```", json.dumps(event, sort_keys=True, indent=2), "```"]
|
|
86
|
-
)
|
|
87
|
-
else:
|
|
88
|
-
error_message = event_detail.get("errorMessage", "")
|
|
89
|
-
# This may be None, in which case we force it to an empty dict instead
|
|
90
|
-
response_element = (event_detail.get("responseElements", {}) or {}).get(
|
|
91
|
-
event_name, ""
|
|
92
|
-
)
|
|
93
|
-
user_identity = event_detail["userIdentity"]
|
|
94
|
-
principal_id = user_identity.get("principalId", "")
|
|
95
|
-
principal_type = user_identity.get("type", "")
|
|
96
|
-
principal_account_id = user_identity.get("accountId", "")
|
|
97
|
-
principal_arn = user_identity.get("arn", "")
|
|
98
|
-
source_ip = event_detail.get("sourceIPAddress", "")
|
|
99
|
-
resources = event_detail.get("resources", []) or []
|
|
100
|
-
text = [
|
|
101
|
-
f"*Event Type:* `{event_type}`",
|
|
102
|
-
f"*Event Name:* `{event_name}`",
|
|
103
|
-
f"*Event Time:* `{event_time}`",
|
|
104
|
-
f"*Error Message:* `{error_message}`" if error_message else "",
|
|
105
|
-
f"*Response Code:* `{response_element}`" if response_element else "",
|
|
106
|
-
f"*Principal Type:* `{principal_type}`" if principal_type else "",
|
|
107
|
-
f"*Principal Account ID:* `{principal_account_id}`"
|
|
108
|
-
if principal_account_id
|
|
109
|
-
else "",
|
|
110
|
-
f"*Principal ARN:* `{principal_arn}`" if principal_arn else "",
|
|
111
|
-
f"*Principal ID:* `{principal_id}`" if principal_id else "",
|
|
112
|
-
f"*Source IP:* `{source_ip}`" if source_ip else "",
|
|
113
|
-
f"*Resources:*\n```{json.dumps(resources, indent=2, sort_keys=True)}\n```"
|
|
114
|
-
if len(resources)
|
|
115
|
-
else "",
|
|
116
|
-
]
|
|
117
|
-
# Filter out empty strings
|
|
118
|
-
text = "\n".join(line for line in text if line)
|
|
119
|
-
|
|
120
|
-
for account_id, friendly_name in account_friendly_names.items():
|
|
121
|
-
pretext = pretext.replace(account_id, friendly_name)
|
|
122
|
-
fallback = fallback.replace(account_id, friendly_name)
|
|
123
|
-
return {
|
|
124
|
-
"attachments": [
|
|
125
|
-
{
|
|
126
|
-
"pretext": pretext,
|
|
127
|
-
"color": "warning",
|
|
128
|
-
"text": text,
|
|
129
|
-
"fallback": fallback,
|
|
130
|
-
"mrkdwn_in": ["pretext", "text"],
|
|
131
|
-
}
|
|
132
|
-
]
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def get_augmented_account_friendly_names(event, account_friendly_names):
|
|
137
|
-
"""Return an augmented dictionary containing the alias of the current
|
|
138
|
-
AWS account if relevant"""
|
|
139
|
-
augmented_account_friendly_names = {**account_friendly_names}
|
|
140
|
-
try:
|
|
141
|
-
event_account_id = event["account"]
|
|
142
|
-
event_detail = event["detail"]
|
|
143
|
-
recipient_account_id = event_detail["recipientAccountId"]
|
|
144
|
-
if (
|
|
145
|
-
not augmented_account_friendly_names.get(event_account_id, "")
|
|
146
|
-
and event_account_id == recipient_account_id
|
|
147
|
-
):
|
|
148
|
-
logger.info(
|
|
149
|
-
"No friendly name was supplied for current account '%s', so looking up account alias",
|
|
150
|
-
event_account_id,
|
|
151
|
-
)
|
|
152
|
-
iam = boto3.client("iam")
|
|
153
|
-
aliases = iam.list_account_aliases()["AccountAliases"]
|
|
154
|
-
if len(aliases):
|
|
155
|
-
augmented_account_friendly_names[event_account_id] = aliases[0]
|
|
156
|
-
except:
|
|
157
|
-
logger.exception("Failed to look up alias of current AWS account")
|
|
158
|
-
|
|
159
|
-
return augmented_account_friendly_names
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def post_to_slack(slack_payload, slack_webhook_url):
|
|
163
|
-
"""Post a payload to Slack's webhook API"""
|
|
164
|
-
encoded_slack_payload = json.dumps(slack_payload).encode("utf-8")
|
|
165
|
-
try:
|
|
166
|
-
slack_request = urllib.request.Request(
|
|
167
|
-
slack_webhook_url,
|
|
168
|
-
data=encoded_slack_payload,
|
|
169
|
-
headers={"Content-Type": "application/json"},
|
|
170
|
-
)
|
|
171
|
-
urllib.request.urlopen(slack_request)
|
|
172
|
-
except:
|
|
173
|
-
logger.exception("Failed to post to Slack")
|
|
174
|
-
raise
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def handler_event_transformer(event, context):
|
|
178
|
-
"""Lambda handler for the event transformer Lambda"""
|
|
179
|
-
logger.info("Triggered with event: %s", json.dumps(event, indent=2))
|
|
180
|
-
|
|
181
|
-
account_friendly_names = json.loads(os.environ["ACCOUNT_FRIENDLY_NAMES"])
|
|
182
|
-
slack_webhook_url = os.environ["SLACK_WEBHOOK_URL"]
|
|
183
|
-
slack_channel = os.environ["SLACK_CHANNEL"]
|
|
184
|
-
sqs_queue_url = os.environ.get("SQS_QUEUE_URL", "")
|
|
185
|
-
fallback_parse_behavior = os.environ.get("FALLBACK_PARSE_BEHAVIOR", "")
|
|
186
|
-
deduplicate_events = os.environ.get("DEDUPLICATE_EVENTS", "false") == "true"
|
|
187
|
-
|
|
188
|
-
account_friendly_names = get_augmented_account_friendly_names(
|
|
189
|
-
event, account_friendly_names
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
if not event["detail-type"].endswith("via CloudTrail"):
|
|
193
|
-
logger.warn("Invalid event received")
|
|
194
|
-
return
|
|
195
|
-
|
|
196
|
-
slack_payload = {}
|
|
197
|
-
try:
|
|
198
|
-
if event["detail"]["eventName"] == "AssumeRole":
|
|
199
|
-
slack_payload = get_slack_payload_for_assume_role_event(
|
|
200
|
-
event, account_friendly_names
|
|
201
|
-
)
|
|
202
|
-
except:
|
|
203
|
-
logger.exception("Failed to parse event using predefined schema")
|
|
204
|
-
if not slack_payload:
|
|
205
|
-
logger.warn("Using a fallback schema to parse event")
|
|
206
|
-
slack_payload = get_fallback_slack_payload_for_event(
|
|
207
|
-
event,
|
|
208
|
-
account_friendly_names,
|
|
209
|
-
fallback_parse_behavior=fallback_parse_behavior,
|
|
210
|
-
)
|
|
211
|
-
slack_payload = {**slack_payload, "channel": slack_channel}
|
|
212
|
-
|
|
213
|
-
if deduplicate_events and sqs_queue_url:
|
|
214
|
-
logger.info("Sending message to SQS for deduplication")
|
|
215
|
-
deduplication_id = (
|
|
216
|
-
event["detail"].get("requestID", "")
|
|
217
|
-
or event["detail"].get("eventID", "")
|
|
218
|
-
or event["id"]
|
|
219
|
-
)
|
|
220
|
-
body = {
|
|
221
|
-
"slackWebhookUrl": slack_webhook_url,
|
|
222
|
-
"slackPayload": slack_payload,
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
sqs = boto3.client("sqs")
|
|
226
|
-
sqs.send_message(
|
|
227
|
-
QueueUrl=sqs_queue_url,
|
|
228
|
-
MessageBody=json.dumps(body),
|
|
229
|
-
MessageDeduplicationId=deduplication_id,
|
|
230
|
-
MessageGroupId=deduplication_id,
|
|
231
|
-
)
|
|
232
|
-
else:
|
|
233
|
-
logger.info("Sending message directly to Slack")
|
|
234
|
-
post_to_slack(slack_payload, slack_webhook_url)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
def handler_slack_forwarder(event, context):
|
|
238
|
-
"""Lambda handler for the Slack forwarder Lambda"""
|
|
239
|
-
logger.info("Triggered with event: %s", json.dumps(event, indent=2))
|
|
240
|
-
records = event["Records"]
|
|
241
|
-
for record in records:
|
|
242
|
-
body = json.loads(record["body"])
|
|
243
|
-
slack_channel = body.get("slackChannel", "")
|
|
244
|
-
slack_webhook_url = body.get("slackWebhookUrl", "")
|
|
245
|
-
slack_payload = {
|
|
246
|
-
**body["slackPayload"],
|
|
247
|
-
**({"channel": slack_channel} if slack_channel else {}),
|
|
248
|
-
}
|
|
249
|
-
post_to_slack(slack_payload, slack_webhook_url)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import * as cdk from "@aws-cdk/core";
|
|
2
|
-
import * as cloudwatch from "@aws-cdk/aws-cloudwatch";
|
|
3
|
-
export interface CloudTrailSlackIntegrationProps extends cdk.StackProps {
|
|
4
|
-
/**
|
|
5
|
-
* A key-value pair of AWS account IDs and friendly names of these accounts
|
|
6
|
-
* to use when sending messages to Slack.
|
|
7
|
-
*/
|
|
8
|
-
accountFriendlyNames?: {
|
|
9
|
-
[key: string]: string;
|
|
10
|
-
};
|
|
11
|
-
slackWebhookUrl: string;
|
|
12
|
-
slackChannel: string;
|
|
13
|
-
/**
|
|
14
|
-
* A list of ARNs of roles in the current account to monitor usage of.
|
|
15
|
-
*/
|
|
16
|
-
rolesToMonitor?: string[];
|
|
17
|
-
/**
|
|
18
|
-
* Whether to monitor various IAM API calls associated with the current account's root user (e.g., console login, password reset, etc.)
|
|
19
|
-
*
|
|
20
|
-
* @default true
|
|
21
|
-
*/
|
|
22
|
-
monitorRootUserActions?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Whether to set up additional AWS infrastructure to deduplicate CloudTrail events in order to avoid duplicate Slack messages. May be used to decrease noise.
|
|
25
|
-
*
|
|
26
|
-
* @default false
|
|
27
|
-
*/
|
|
28
|
-
deduplicateEvents?: boolean;
|
|
29
|
-
/**
|
|
30
|
-
* If supplied, CloudWatch alarms will be created for the construct's underlying infrastructure (e.g., Lambda functions) and the action will be used to notify on OK and ALARM actions.
|
|
31
|
-
*/
|
|
32
|
-
infrastructureAlarmAction?: cloudwatch.IAlarmAction;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Forward a predefined set of CloudTrail API events to Slack using EventBridge, Lambda
|
|
36
|
-
* and an optional SQS FIFO queue for deduplicating events.
|
|
37
|
-
* The API events are limited to monitoring access to the current account's root user and/or specific IAM roles.
|
|
38
|
-
*
|
|
39
|
-
* NOTE: The construct needs to be provisioned in us-east-1, and requires an existing CloudTrail set up in that region.
|
|
40
|
-
*/
|
|
41
|
-
export declare class CloudTrailSlackIntegration extends cdk.Construct {
|
|
42
|
-
constructor(scope: cdk.Construct, id: string, props: CloudTrailSlackIntegrationProps);
|
|
43
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CloudTrailSlackIntegration = void 0;
|
|
4
|
-
const cdk = require("@aws-cdk/core");
|
|
5
|
-
const iam = require("@aws-cdk/aws-iam");
|
|
6
|
-
const logs = require("@aws-cdk/aws-logs");
|
|
7
|
-
const cloudwatch = require("@aws-cdk/aws-cloudwatch");
|
|
8
|
-
const lambda = require("@aws-cdk/aws-lambda");
|
|
9
|
-
const events = require("@aws-cdk/aws-events");
|
|
10
|
-
const sources = require("@aws-cdk/aws-lambda-event-sources");
|
|
11
|
-
const sqs = require("@aws-cdk/aws-sqs");
|
|
12
|
-
const targets = require("@aws-cdk/aws-events-targets");
|
|
13
|
-
const path = require("path");
|
|
14
|
-
/**
|
|
15
|
-
* Forward a predefined set of CloudTrail API events to Slack using EventBridge, Lambda
|
|
16
|
-
* and an optional SQS FIFO queue for deduplicating events.
|
|
17
|
-
* The API events are limited to monitoring access to the current account's root user and/or specific IAM roles.
|
|
18
|
-
*
|
|
19
|
-
* NOTE: The construct needs to be provisioned in us-east-1, and requires an existing CloudTrail set up in that region.
|
|
20
|
-
*/
|
|
21
|
-
class CloudTrailSlackIntegration extends cdk.Construct {
|
|
22
|
-
constructor(scope, id, props) {
|
|
23
|
-
super(scope, id);
|
|
24
|
-
const eventTransformer = new lambda.Function(this, "EventTransformerLambda", {
|
|
25
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "../../assets/cloudtrail-slack-integration-lambda")),
|
|
26
|
-
description: "Formats CloudTrail API calls sent through EventBridge, and posts them directly to Slack or first to an SQS FIFO queue for deduplication",
|
|
27
|
-
handler: "main.handler_event_transformer",
|
|
28
|
-
runtime: lambda.Runtime.PYTHON_3_9,
|
|
29
|
-
timeout: cdk.Duration.seconds(15),
|
|
30
|
-
logRetention: logs.RetentionDays.SIX_MONTHS,
|
|
31
|
-
environment: {
|
|
32
|
-
SLACK_CHANNEL: props.slackChannel,
|
|
33
|
-
DEDUPLICATE_EVENTS: JSON.stringify(!!props.deduplicateEvents),
|
|
34
|
-
ACCOUNT_FRIENDLY_NAMES: JSON.stringify(props.accountFriendlyNames || {}),
|
|
35
|
-
SLACK_WEBHOOK_URL: props.slackWebhookUrl,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
eventTransformer.addToRolePolicy(new iam.PolicyStatement({
|
|
39
|
-
actions: ["iam:ListAccountAliases"],
|
|
40
|
-
resources: ["*"],
|
|
41
|
-
}));
|
|
42
|
-
if (props.infrastructureAlarmAction) {
|
|
43
|
-
const eventTransformerAlarm = eventTransformer
|
|
44
|
-
.metricErrors({
|
|
45
|
-
period: cdk.Duration.minutes(5),
|
|
46
|
-
statistic: cloudwatch.Statistic.SUM,
|
|
47
|
-
})
|
|
48
|
-
.createAlarm(this, "EventTransformerErrorAlarm", {
|
|
49
|
-
threshold: 1,
|
|
50
|
-
evaluationPeriods: 1,
|
|
51
|
-
alarmDescription: "Triggers if the Lambda function that transforms CloudTrail API calls received through EventBridge fails (e.g., it fails to process the event)",
|
|
52
|
-
datapointsToAlarm: 1,
|
|
53
|
-
treatMissingData: cloudwatch.TreatMissingData.IGNORE,
|
|
54
|
-
});
|
|
55
|
-
eventTransformerAlarm.addOkAction(props.infrastructureAlarmAction);
|
|
56
|
-
eventTransformerAlarm.addAlarmAction(props.infrastructureAlarmAction);
|
|
57
|
-
}
|
|
58
|
-
if (props.deduplicateEvents) {
|
|
59
|
-
const deduplicationQueue = new sqs.Queue(this, "Queue", {
|
|
60
|
-
// We explicitly give the queue a name due to bug https://github.com/aws/aws-cdk/issues/5860
|
|
61
|
-
queueName: `${this.node.id.substring(0, 33)}${this.node.addr}`.substring(0, 75) +
|
|
62
|
-
".fifo",
|
|
63
|
-
fifo: true,
|
|
64
|
-
});
|
|
65
|
-
eventTransformer.addEnvironment("SQS_QUEUE_URL", deduplicationQueue.queueUrl);
|
|
66
|
-
deduplicationQueue.grantSendMessages(eventTransformer);
|
|
67
|
-
const slackForwarder = new lambda.Function(this, "SlackForwarderLambda", {
|
|
68
|
-
code: lambda.Code.fromAsset(path.join(__dirname, "../../assets/cloudtrail-slack-integration-lambda")),
|
|
69
|
-
description: "Polls from an SQS FIFO queue containing formatted CloudTrail API calls and sends them to Slack.",
|
|
70
|
-
handler: "main.handler_slack_forwarder",
|
|
71
|
-
runtime: lambda.Runtime.PYTHON_3_9,
|
|
72
|
-
timeout: cdk.Duration.seconds(15),
|
|
73
|
-
logRetention: logs.RetentionDays.TWO_WEEKS,
|
|
74
|
-
});
|
|
75
|
-
if (props.infrastructureAlarmAction) {
|
|
76
|
-
const slackForwarderAlarm = slackForwarder
|
|
77
|
-
.metricErrors({
|
|
78
|
-
period: cdk.Duration.minutes(5),
|
|
79
|
-
statistic: cloudwatch.Statistic.SUM,
|
|
80
|
-
})
|
|
81
|
-
.createAlarm(this, "SlackForwarderErrorAlarm", {
|
|
82
|
-
threshold: 1,
|
|
83
|
-
alarmDescription: "Triggers if the Lambda function that polls from SQS and posts deduplicated CloudTrail API calls received through EventBridge to Slack fails (e.g., invalid Slack webhook URL)",
|
|
84
|
-
evaluationPeriods: 1,
|
|
85
|
-
datapointsToAlarm: 1,
|
|
86
|
-
treatMissingData: cloudwatch.TreatMissingData.IGNORE,
|
|
87
|
-
});
|
|
88
|
-
slackForwarderAlarm.addOkAction(props.infrastructureAlarmAction);
|
|
89
|
-
slackForwarderAlarm.addAlarmAction(props.infrastructureAlarmAction);
|
|
90
|
-
}
|
|
91
|
-
slackForwarder.addEventSource(new sources.SqsEventSource(deduplicationQueue));
|
|
92
|
-
}
|
|
93
|
-
if (props.rolesToMonitor && props.rolesToMonitor.length > 0) {
|
|
94
|
-
new events.Rule(this, "RuleForAssumeRole", {
|
|
95
|
-
enabled: true,
|
|
96
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
97
|
-
eventPattern: {
|
|
98
|
-
detail: {
|
|
99
|
-
eventName: ["AssumeRole"],
|
|
100
|
-
requestParameters: {
|
|
101
|
-
roleArn: props.rolesToMonitor,
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
if (props.monitorRootUserActions !== false) {
|
|
108
|
-
// Triggers when the root password has been changed
|
|
109
|
-
new events.Rule(this, "RuleForRootUserPasswordChange", {
|
|
110
|
-
enabled: true,
|
|
111
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
112
|
-
eventPattern: {
|
|
113
|
-
detail: {
|
|
114
|
-
userIdentity: {
|
|
115
|
-
type: ["Root"],
|
|
116
|
-
},
|
|
117
|
-
eventName: ["PasswordUpdated"],
|
|
118
|
-
eventType: ["AwsConsoleSignIn"],
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
// Triggers when MFA for the root user has been set up
|
|
123
|
-
new events.Rule(this, "RuleForRootUserMfaChange", {
|
|
124
|
-
enabled: true,
|
|
125
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
126
|
-
eventPattern: {
|
|
127
|
-
detail: {
|
|
128
|
-
userIdentity: {
|
|
129
|
-
type: ["Root"],
|
|
130
|
-
},
|
|
131
|
-
eventName: ["EnableMFADevice"],
|
|
132
|
-
requestParameters: {
|
|
133
|
-
userName: ["AWS ROOT USER"],
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
// Triggers when a root user succesfully logs in to the console
|
|
139
|
-
new events.Rule(this, "RuleForRootUserSuccessfulLogin", {
|
|
140
|
-
enabled: true,
|
|
141
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
142
|
-
eventPattern: {
|
|
143
|
-
detail: {
|
|
144
|
-
userIdentity: {
|
|
145
|
-
type: ["Root"],
|
|
146
|
-
},
|
|
147
|
-
eventName: ["ConsoleLogin"],
|
|
148
|
-
eventType: ["AwsConsoleSignIn"],
|
|
149
|
-
responseElements: {
|
|
150
|
-
ConsoleLogin: ["Success"],
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
// Triggers for bad login attemps for root user (e.g., wrong password)
|
|
156
|
-
new events.Rule(this, "RuleForRootUserUnsuccessfulLogin", {
|
|
157
|
-
enabled: true,
|
|
158
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
159
|
-
eventPattern: {
|
|
160
|
-
detail: {
|
|
161
|
-
userIdentity: {
|
|
162
|
-
type: ["Root"],
|
|
163
|
-
},
|
|
164
|
-
eventName: ["ConsoleLogin"],
|
|
165
|
-
eventType: ["AwsConsoleSignIn"],
|
|
166
|
-
responseElements: {
|
|
167
|
-
ConsoleLogin: ["Failure"],
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
// Triggered when password reset has been requested
|
|
173
|
-
new events.Rule(this, "RuleForRootUserPasswordRecoveryRequest", {
|
|
174
|
-
enabled: true,
|
|
175
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
176
|
-
eventPattern: {
|
|
177
|
-
detail: {
|
|
178
|
-
userIdentity: {
|
|
179
|
-
type: ["Root"],
|
|
180
|
-
},
|
|
181
|
-
eventName: ["PasswordRecoveryRequested"],
|
|
182
|
-
eventType: ["AwsConsoleSignIn"],
|
|
183
|
-
responseElements: {
|
|
184
|
-
PasswordRecoveryRequested: ["Success"],
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
});
|
|
189
|
-
// Triggered when password has been successfully reset
|
|
190
|
-
new events.Rule(this, "RuleForRootUserPasswordRecoveryComplete", {
|
|
191
|
-
enabled: true,
|
|
192
|
-
targets: [new targets.LambdaFunction(eventTransformer)],
|
|
193
|
-
eventPattern: {
|
|
194
|
-
detail: {
|
|
195
|
-
userIdentity: {
|
|
196
|
-
type: ["Root"],
|
|
197
|
-
},
|
|
198
|
-
eventName: ["PasswordRecoveryCompleted"],
|
|
199
|
-
eventType: ["AwsConsoleSignIn"],
|
|
200
|
-
responseElements: {
|
|
201
|
-
PasswordRecoveryCompleted: ["Success"],
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
exports.CloudTrailSlackIntegration = CloudTrailSlackIntegration;
|
|
210
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWR0cmFpbC1zbGFjay1pbnRlZ3JhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbG91ZHRyYWlsLXNsYWNrLWludGVncmF0aW9uL2Nsb3VkdHJhaWwtc2xhY2staW50ZWdyYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUNBQW9DO0FBQ3BDLHdDQUF1QztBQUN2QywwQ0FBeUM7QUFDekMsc0RBQXFEO0FBQ3JELDhDQUE2QztBQUM3Qyw4Q0FBNkM7QUFDN0MsNkRBQTREO0FBQzVELHdDQUF1QztBQUN2Qyx1REFBc0Q7QUFDdEQsNkJBQTRCO0FBa0M1Qjs7Ozs7O0dBTUc7QUFDSCxNQUFhLDBCQUEyQixTQUFRLEdBQUcsQ0FBQyxTQUFTO0lBQzNELFlBQ0UsS0FBb0IsRUFDcEIsRUFBVSxFQUNWLEtBQXNDO1FBRXRDLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFFaEIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQzFDLElBQUksRUFDSix3QkFBd0IsRUFDeEI7WUFDRSxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQ3pCLElBQUksQ0FBQyxJQUFJLENBQ1AsU0FBUyxFQUNULGtEQUFrRCxDQUNuRCxDQUNGO1lBQ0QsV0FBVyxFQUNULHlJQUF5STtZQUMzSSxPQUFPLEVBQUUsZ0NBQWdDO1lBQ3pDLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVU7WUFDbEMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNqQyxZQUFZLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVO1lBQzNDLFdBQVcsRUFBRTtnQkFDWCxhQUFhLEVBQUUsS0FBSyxDQUFDLFlBQVk7Z0JBQ2pDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxp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QUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztnQkFDdkQsWUFBWSxFQUFFO29CQUNaLE1BQU0sRUFBRTt3QkFDTixZQUFZLEVBQUU7NEJBQ1osSUFBSSxFQUFFLENBQUMsTUFBTSxDQUFDO3lCQUNmO3dCQUNELFNBQVMsRUFBRSxDQUFDLDJCQUEyQixDQUFDO3dCQUN4QyxTQUFTLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQzt3QkFDL0IsZ0JBQWdCLEVBQUU7NEJBQ2hCLHlCQUF5QixFQUFFLENBQUMsU0FBUyxDQUFDO3lCQUN2QztxQkFDRjtpQkFDRjthQUNGLENBQUMsQ0FBQTtTQUNIO0lBQ0gsQ0FBQztDQUNGO0FBcE9ELGdFQW9PQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNkayBmcm9tIFwiQGF3cy1jZGsvY29yZVwiXG5pbXBvcnQgKiBhcyBpYW0gZnJvbSBcIkBhd3MtY2RrL2F3cy1pYW1cIlxuaW1wb3J0ICogYXMgbG9ncyBmcm9tIFwiQGF3cy1jZGsvYXdzLWxvZ3NcIlxuaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tIFwiQGF3cy1jZGsvYXdzLWNsb3Vkd2F0Y2hcIlxuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gXCJAYXdzLWNkay9hd3MtbGFtYmRhXCJcbmltcG9ydCAqIGFzIGV2ZW50cyBmcm9tIFwiQGF3cy1jZGsvYXdzLWV2ZW50c1wiXG5pbXBvcnQgKiBhcyBzb3VyY2VzIGZyb20gXCJAYXdzLWNkay9hd3MtbGFtYmRhLWV2ZW50LXNvdXJjZXNcIlxuaW1wb3J0ICogYXMgc3FzIGZyb20gXCJAYXdzLWNkay9hd3Mtc3FzXCJcbmltcG9ydCAqIGFzIHRhcmdldHMgZnJvbSBcIkBhd3MtY2RrL2F3cy1ldmVudHMtdGFyZ2V0c1wiXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCJcblxuZXhwb3J0IGludGVyZmFjZSBDbG91ZFRyYWlsU2xhY2tJbnRlZ3JhdGlvblByb3BzIGV4dGVuZHMgY2RrLlN0YWNrUHJvcHMge1xuICAvKipcbiAgICogQSBrZXktdmFsdWUgcGFpciBvZiBBV1MgYWNjb3VudCBJRHMgYW5kIGZyaWVuZGx5IG5hbWVzIG9mIHRoZXNlIGFjY291bnRzXG4gICAqIHRvIHVzZSB3aGVuIHNlbmRpbmcgbWVzc2FnZXMgdG8gU2xhY2suXG4gICAqL1xuICBhY2NvdW50RnJpZW5kbHlOYW1lcz86IHtcbiAgICBba2V5OiBzdHJpbmddOiBzdHJpbmdcbiAgfVxuICBzbGFja1dlYmhvb2tVcmw6IHN0cmluZ1xuICBzbGFja0NoYW5uZWw6IHN0cmluZ1xuICAvKipcbiAgICogQSBsaXN0IG9mIEFSTnMgb2Ygcm9sZXMgaW4gdGhlIGN1cnJlbnQgYWNjb3VudCB0byBtb25pdG9yIHVzYWdlIG9mLlxuICAgKi9cbiAgcm9sZXNUb01vbml0b3I/OiBzdHJpbmdbXVxuICAvKipcbiAgICogV2hldGhlciB0byBtb25pdG9yIHZhcmlvdXMgSUFNIEFQSSBjYWxscyBhc3NvY2lhdGVkIHdpdGggdGhlIGN1cnJlbnQgYWNjb3VudCdzIHJvb3QgdXNlciAoZS5nLiwgY29uc29sZSBsb2dpbiwgcGFzc3dvcmQgcmVzZXQsIGV0Yy4pXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIG1vbml0b3JSb290VXNlckFjdGlvbnM/OiBib29sZWFuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHNldCB1cCBhZGRpdGlvbmFsIEFXUyBpbmZyYXN0cnVjdHVyZSB0byBkZWR1cGxpY2F0ZSBDbG91ZFRyYWlsIGV2ZW50cyBpbiBvcmRlciB0byBhdm9pZCBkdXBsaWNhdGUgU2xhY2sgbWVzc2FnZXMuIE1heSBiZSB1c2VkIHRvIGRlY3JlYXNlIG5vaXNlLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgZGVkdXBsaWNhdGVFdmVudHM/OiBib29sZWFuXG4gIC8qKlxuICAgKiBJZiBzdXBwbGllZCwgQ2xvdWRXYXRjaCBhbGFybXMgd2lsbCBiZSBjcmVhdGVkIGZvciB0aGUgY29uc3RydWN0J3MgdW5kZXJseWluZyBpbmZyYXN0cnVjdHVyZSAoZS5nLiwgTGFtYmRhIGZ1bmN0aW9ucykgYW5kIHRoZSBhY3Rpb24gd2lsbCBiZSB1c2VkIHRvIG5vdGlmeSBvbiBPSyBhbmQgQUxBUk0gYWN0aW9ucy5cbiAgICovXG4gIGluZnJhc3RydWN0dXJlQWxhcm1BY3Rpb24/OiBjbG91ZHdhdGNoLklBbGFybUFjdGlvblxufVxuXG4vKipcbiAqIEZvcndhcmQgYSBwcmVkZWZpbmVkIHNldCBvZiBDbG91ZFRyYWlsIEFQSSBldmVudHMgdG8gU2xhY2sgdXNpbmcgRXZlbnRCcmlkZ2UsIExhbWJkYVxuICogYW5kIGFuIG9wdGlvbmFsIFNRUyBGSUZPIHF1ZXVlIGZvciBkZWR1cGxpY2F0aW5nIGV2ZW50cy5cbiAqIFRoZSBBUEkgZXZlbnRzIGFyZSBsaW1pdGVkIHRvIG1vbml0b3JpbmcgYWNjZXNzIHRvIHRoZSBjdXJyZW50IGFjY291bnQncyByb290IHVzZXIgYW5kL29yIHNwZWNpZmljIElBTSByb2xlcy5cbiAqXG4gKiBOT1RFOiBUaGUgY29uc3RydWN0IG5lZWRzIHRvIGJlIHByb3Zpc2lvbmVkIGluIHVzLWVhc3QtMSwgYW5kIHJlcXVpcmVzIGFuIGV4aXN0aW5nIENsb3VkVHJhaWwgc2V0IHVwIGluIHRoYXQgcmVnaW9uLlxuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRUcmFpbFNsYWNrSW50ZWdyYXRpb24gZXh0ZW5kcyBjZGsuQ29uc3RydWN0IHtcbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IGNkay5Db25zdHJ1Y3QsXG4gICAgaWQ6IHN0cmluZyxcbiAgICBwcm9wczogQ2xvdWRUcmFpbFNsYWNrSW50ZWdyYXRpb25Qcm9wcyxcbiAgKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKVxuXG4gICAgY29uc3QgZXZlbnRUcmFuc2Zvcm1lciA9IG5ldyBsYW1iZGEuRnVuY3Rpb24oXG4gICAgICB0aGlzLFxuICAgICAgXCJFdmVudFRyYW5zZm9ybWVyTGFtYmRhXCIsXG4gICAgICB7XG4gICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChcbiAgICAgICAgICBwYXRoLmpvaW4oXG4gICAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgICBcIi4uLy4uL2Fzc2V0cy9jbG91ZHRyYWlsLXNsYWNrLWludGVncmF0aW9uLWxhbWJkYVwiLFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgIFwiRm9ybWF0cyBDbG91ZFRyYWlsIEFQSSBjYWxscyBzZW50IHRocm91Z2ggRXZlbnRCcmlkZ2UsIGFuZCBwb3N0cyB0aGVtIGRpcmVjdGx5IHRvIFNsYWNrIG9yIGZpcnN0IHRvIGFuIFNRUyBGSUZPIHF1ZXVlIGZvciBkZWR1cGxpY2F0aW9uXCIsXG4gICAgICAgIGhhbmRsZXI6IFwibWFpbi5oYW5kbGVyX2V2ZW50X3RyYW5zZm9ybWVyXCIsXG4gICAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzksXG4gICAgICAgIHRpbWVvdXQ6IGNkay5EdXJhdGlvbi5zZWNvbmRzKDE1KSxcbiAgICAgICAgbG9nUmV0ZW50aW9uOiBsb2dzLlJldGVudGlvbkRheXMuU0lYX01PTlRIUyxcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICBTTEFDS19DSEFOTkVMOiBwcm9wcy5zbGFja0NoYW5uZWwsXG4gICAgICAgICAgREVEVVBMSUNBVEVfRVZFTlRTOiBKU09OLnN0cmluZ2lmeSghIXByb3BzLmRlZHVwbGljYXRlRXZlbnRzKSxcbiAgICAgICAgICBBQ0NPVU5UX0ZSSUVORExZX05BTUVTOiBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgIHByb3BzLmFjY291bnRGcmllbmRseU5hbWVzIHx8IHt9LFxuICAgICAgICAgICksXG4gICAgICAgICAgU0xBQ0tfV0VCSE9PS19VUkw6IHByb3BzLnNsYWNrV2ViaG9va1VybCxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgKVxuICAgIGV2ZW50VHJhbnNmb3JtZXIuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbXCJpYW06TGlzdEFjY291bnRBbGlhc2VzXCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICB9KSxcbiAgICApXG4gICAgaWYgKHByb3BzLmluZnJhc3RydWN0dXJlQWxhcm1BY3Rpb24pIHtcbiAgICAgIGNvbnN0IGV2ZW50VHJhbnNmb3JtZXJBbGFybSA9IGV2ZW50VHJhbnNmb3JtZXJcbiAgICAgICAgLm1ldHJpY0Vycm9ycyh7XG4gICAgICAgICAgcGVyaW9kOiBjZGsuRHVyYXRpb24ubWludXRlcyg1KSxcbiAgICAgICAgICBzdGF0aXN0aWM6IGNsb3Vkd2F0Y2guU3RhdGlzdGljLlNVTSxcbiAgICAgICAgfSlcbiAgICAgICAgLmNyZWF0ZUFsYXJtKHRoaXMsIFwiRXZlbnRUcmFuc2Zvcm1lckVycm9yQWxhcm1cIiwge1xuICAgICAgICAgIHRocmVzaG9sZDogMSxcbiAgICAgICAgICBldmFsdWF0aW9uUGVyaW9kczogMSxcbiAgICAgICAgICBhbGFybURlc2NyaXB0aW9uOlxuICAgICAgICAgICAgXCJUcmlnZ2VycyBpZiB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRoYXQgdHJhbnNmb3JtcyBDbG91ZFRyYWlsIEFQSSBjYWxscyByZWNlaXZlZCB0aHJvdWdoIEV2ZW50QnJpZGdlIGZhaWxzIChlLmcuLCBpdCBmYWlscyB0byBwcm9jZXNzIHRoZSBldmVudClcIixcbiAgICAgICAgICBkYXRhcG9pbnRzVG9BbGFybTogMSxcbiAgICAgICAgICB0cmVhdE1pc3NpbmdEYXRhOiBjbG91ZHdhdGNoLlRyZWF0TWlzc2luZ0RhdGEuSUdOT1JFLFxuICAgICAgICB9KVxuICAgICAgZXZlbnRUcmFuc2Zvcm1lckFsYXJtLmFkZE9rQWN0aW9uKHByb3BzLmluZnJhc3RydWN0dXJlQWxhcm1BY3Rpb24pXG4gICAgICBldmVudFRyYW5zZm9ybWVyQWxhcm0uYWRkQWxhcm1BY3Rpb24ocHJvcHMuaW5mcmFzdHJ1Y3R1cmVBbGFybUFjdGlvbilcbiAgICB9XG4gICAgaWYgKHByb3BzLmRlZHVwbGljYXRlRXZlbnRzKSB7XG4gICAgICBjb25zdCBkZWR1cGxpY2F0aW9uUXVldWUgPSBuZXcgc3FzLlF1ZXVlKHRoaXMsIFwiUXVldWVcIiwge1xuICAgICAgICAvLyBXZSBleHBsaWNpdGx5IGdpdmUgdGhlIHF1ZXVlIGEgbmFtZSBkdWUgdG8gYnVnIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvNTg2MFxuICAgICAgICBxdWV1ZU5hbWU6XG4gICAgICAgICAgYCR7dGhpcy5ub2RlLmlkLnN1YnN0cmluZygwLCAzMyl9JHt0aGlzLm5vZGUuYWRkcn1gLnN1YnN0cmluZygwLCA3NSkgK1xuICAgICAgICAgIFwiLmZpZm9cIixcbiAgICAgICAgZmlmbzogdHJ1ZSxcbiAgICAgIH0pXG4gICAgICBldmVudFRyYW5zZm9ybWVyLmFkZEVudmlyb25tZW50KFxuICAgICAgICBcIlNRU19RVUVVRV9VUkxcIixcbiAgICAgICAgZGVkdXBsaWNhdGlvblF1ZXVlLnF1ZXVlVXJsLFxuICAgICAgKVxuICAgICAgZGVkdXBsaWNhdGlvblF1ZXVlLmdyYW50U2VuZE1lc3NhZ2VzKGV2ZW50VHJhbnNmb3JtZXIpXG4gICAgICBjb25zdCBzbGFja0ZvcndhcmRlciA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgXCJTbGFja0ZvcndhcmRlckxhbWJkYVwiLCB7XG4gICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChcbiAgICAgICAgICBwYXRoLmpvaW4oXG4gICAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgICBcIi4uLy4uL2Fzc2V0cy9jbG91ZHRyYWlsLXNsYWNrLWludGVncmF0aW9uLWxhbWJkYVwiLFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgIFwiUG9sbHMgZnJvbSBhbiBTUVMgRklGTyBxdWV1ZSBjb250YWluaW5nIGZvcm1hdHRlZCBDbG91ZFRyYWlsIEFQSSBjYWxscyBhbmQgc2VuZHMgdGhlbSB0byBTbGFjay5cIixcbiAgICAgICAgaGFuZGxlcjogXCJtYWluLmhhbmRsZXJfc2xhY2tfZm9yd2FyZGVyXCIsXG4gICAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzksXG4gICAgICAgIHRpbWVvdXQ6IGNkay5EdXJhdGlvbi5zZWNvbmRzKDE1KSxcbiAgICAgICAgbG9nUmV0ZW50aW9uOiBsb2dzLlJldGVudGlvbkRheXMuVFdPX1dFRUtTLFxuICAgICAgfSlcblxuICAgICAgaWYgKHByb3BzLmluZnJhc3RydWN0dXJlQWxhcm1BY3Rpb24pIHtcbiAgICAgICAgY29uc3Qgc2xhY2tGb3J3YXJkZXJBbGFybSA9IHNsYWNrRm9yd2FyZGVyXG4gICAgICAgICAgLm1ldHJpY0Vycm9ycyh7XG4gICAgICAgICAgICBwZXJpb2Q6IGNkay5EdXJhdGlvbi5taW51dGVzKDUpLFxuICAgICAgICAgICAgc3RhdGlzdGljOiBjbG91ZHdhdGNoLlN0YXRpc3RpYy5TVU0sXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY3JlYXRlQWxhcm0odGhpcywgXCJTbGFja0ZvcndhcmRlckVycm9yQWxhcm1cIiwge1xuICAgICAgICAgICAgdGhyZXNob2xkOiAxLFxuICAgICAgICAgICAgYWxhcm1EZXNjcmlwdGlvbjpcbiAgICAgICAgICAgICAgXCJUcmlnZ2VycyBpZiB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRoYXQgcG9sbHMgZnJvbSBTUVMgYW5kIHBvc3RzIGRlZHVwbGljYXRlZCBDbG91ZFRyYWlsIEFQSSBjYWxscyByZWNlaXZlZCB0aHJvdWdoIEV2ZW50QnJpZGdlIHRvIFNsYWNrIGZhaWxzIChlLmcuLCBpbnZhbGlkIFNsYWNrIHdlYmhvb2sgVVJMKVwiLFxuICAgICAgICAgICAgZXZhbHVhdGlvblBlcmlvZHM6IDEsXG4gICAgICAgICAgICBkYXRhcG9pbnRzVG9BbGFybTogMSxcbiAgICAgICAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IGNsb3Vkd2F0Y2guVHJlYXRNaXNzaW5nRGF0YS5JR05PUkUsXG4gICAgICAgICAgfSlcbiAgICAgICAgc2xhY2tGb3J3YXJkZXJBbGFybS5hZGRPa0FjdGlvbihwcm9wcy5pbmZyYXN0cnVjdHVyZUFsYXJtQWN0aW9uKVxuICAgICAgICBzbGFja0ZvcndhcmRlckFsYXJtLmFkZEFsYXJtQWN0aW9uKHByb3BzLmluZnJhc3RydWN0dXJlQWxhcm1BY3Rpb24pXG4gICAgICB9XG4gICAgICBzbGFja0ZvcndhcmRlci5hZGRFdmVudFNvdXJjZShcbiAgICAgICAgbmV3IHNvdXJjZXMuU3FzRXZlbnRTb3VyY2UoZGVkdXBsaWNhdGlvblF1ZXVlKSxcbiAgICAgIClcbiAgICB9XG5cbiAgICBpZiAocHJvcHMucm9sZXNUb01vbml0b3IgJiYgcHJvcHMucm9sZXNUb01vbml0b3IubGVuZ3RoID4gMCkge1xuICAgICAgbmV3IGV2ZW50cy5SdWxlKHRoaXMsIFwiUnVsZUZvckFzc3VtZVJvbGVcIiwge1xuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgICB0YXJnZXRzOiBbbmV3IHRhcmdldHMuTGFtYmRhRnVuY3Rpb24oZXZlbnRUcmFuc2Zvcm1lcildLFxuICAgICAgICBldmVudFBhdHRlcm46IHtcbiAgICAgICAgICBkZXRhaWw6IHtcbiAgICAgICAgICAgIGV2ZW50TmFtZTogW1wiQXNzdW1lUm9sZVwiXSxcbiAgICAgICAgICAgIHJlcXVlc3RQYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgICAgIHJvbGVBcm46IHByb3BzLnJvbGVzVG9Nb25pdG9yLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9XG5cbiAgICBpZiAocHJvcHMubW9uaXRvclJvb3RVc2VyQWN0aW9ucyAhPT0gZmFsc2UpIHtcbiAgICAgIC8vIFRyaWdnZXJzIHdoZW4gdGhlIHJvb3QgcGFzc3dvcmQgaGFzIGJlZW4gY2hhbmdlZFxuICAgICAgbmV3IGV2ZW50cy5SdWxlKHRoaXMsIFwiUnVsZUZvclJvb3RVc2VyUGFzc3dvcmRDaGFuZ2VcIiwge1xuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgICB0YXJnZXRzOiBbbmV3IHRhcmdldHMuTGFtYmRhRnVuY3Rpb24oZXZlbnRUcmFuc2Zvcm1lcildLFxuICAgICAgICBldmVudFBhdHRlcm46IHtcbiAgICAgICAgICBkZXRhaWw6IHtcbiAgICAgICAgICAgIHVzZXJJZGVudGl0eToge1xuICAgICAgICAgICAgICB0eXBlOiBbXCJSb290XCJdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGV2ZW50TmFtZTogW1wiUGFzc3dvcmRVcGRhdGVkXCJdLFxuICAgICAgICAgICAgZXZlbnRUeXBlOiBbXCJBd3NDb25zb2xlU2lnbkluXCJdLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuXG4gICAgICAvLyBUcmlnZ2VycyB3aGVuIE1GQSBmb3IgdGhlIHJvb3QgdXNlciBoYXMgYmVlbiBzZXQgdXBcbiAgICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCBcIlJ1bGVGb3JSb290VXNlck1mYUNoYW5nZVwiLCB7XG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICAgIHRhcmdldHM6IFtuZXcgdGFyZ2V0cy5MYW1iZGFGdW5jdGlvbihldmVudFRyYW5zZm9ybWVyKV0sXG4gICAgICAgIGV2ZW50UGF0dGVybjoge1xuICAgICAgICAgIGRldGFpbDoge1xuICAgICAgICAgICAgdXNlcklkZW50aXR5OiB7XG4gICAgICAgICAgICAgIHR5cGU6IFtcIlJvb3RcIl0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZXZlbnROYW1lOiBbXCJFbmFibGVNRkFEZXZpY2VcIl0sXG4gICAgICAgICAgICByZXF1ZXN0UGFyYW1ldGVyczoge1xuICAgICAgICAgICAgICB1c2VyTmFtZTogW1wiQVdTIFJPT1QgVVNFUlwiXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pXG5cbiAgICAgIC8vIFRyaWdnZXJzIHdoZW4gYSByb290IHVzZXIgc3VjY2VzZnVsbHkgbG9ncyBpbiB0byB0aGUgY29uc29sZVxuICAgICAgbmV3IGV2ZW50cy5SdWxlKHRoaXMsIFwiUnVsZUZvclJvb3RVc2VyU3VjY2Vzc2Z1bExvZ2luXCIsIHtcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgdGFyZ2V0czogW25ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGV2ZW50VHJhbnNmb3JtZXIpXSxcbiAgICAgICAgZXZlbnRQYXR0ZXJuOiB7XG4gICAgICAgICAgZGV0YWlsOiB7XG4gICAgICAgICAgICB1c2VySWRlbnRpdHk6IHtcbiAgICAgICAgICAgICAgdHlwZTogW1wiUm9vdFwiXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBldmVudE5hbWU6IFtcIkNvbnNvbGVMb2dpblwiXSxcbiAgICAgICAgICAgIGV2ZW50VHlwZTogW1wiQXdzQ29uc29sZVNpZ25JblwiXSxcbiAgICAgICAgICAgIHJlc3BvbnNlRWxlbWVudHM6IHtcbiAgICAgICAgICAgICAgQ29uc29sZUxvZ2luOiBbXCJTdWNjZXNzXCJdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcblxuICAgICAgLy8gVHJpZ2dlcnMgZm9yIGJhZCBsb2dpbiBhdHRlbXBzIGZvciByb290IHVzZXIgKGUuZy4sIHdyb25nIHBhc3N3b3JkKVxuICAgICAgbmV3IGV2ZW50cy5SdWxlKHRoaXMsIFwiUnVsZUZvclJvb3RVc2VyVW5zdWNjZXNzZnVsTG9naW5cIiwge1xuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgICB0YXJnZXRzOiBbbmV3IHRhcmdldHMuTGFtYmRhRnVuY3Rpb24oZXZlbnRUcmFuc2Zvcm1lcildLFxuICAgICAgICBldmVudFBhdHRlcm46IHtcbiAgICAgICAgICBkZXRhaWw6IHtcbiAgICAgICAgICAgIHVzZXJJZGVudGl0eToge1xuICAgICAgICAgICAgICB0eXBlOiBbXCJSb290XCJdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGV2ZW50TmFtZTogW1wiQ29uc29sZUxvZ2luXCJdLFxuICAgICAgICAgICAgZXZlbnRUeXBlOiBbXCJBd3NDb25zb2xlU2lnbkluXCJdLFxuICAgICAgICAgICAgcmVzcG9uc2VFbGVtZW50czoge1xuICAgICAgICAgICAgICBDb25zb2xlTG9naW46IFtcIkZhaWx1cmVcIl0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuXG4gICAgICAvLyBUcmlnZ2VyZWQgd2hlbiBwYXNzd29yZCByZXNldCBoYXMgYmVlbiByZXF1ZXN0ZWRcbiAgICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCBcIlJ1bGVGb3JSb290VXNlclBhc3N3b3JkUmVjb3ZlcnlSZXF1ZXN0XCIsIHtcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgdGFyZ2V0czogW25ldyB0YXJnZXRzLkxhbWJkYUZ1bmN0aW9uKGV2ZW50VHJhbnNmb3JtZXIpXSxcbiAgICAgICAgZXZlbnRQYXR0ZXJuOiB7XG4gICAgICAgICAgZGV0YWlsOiB7XG4gICAgICAgICAgICB1c2VySWRlbnRpdHk6IHtcbiAgICAgICAgICAgICAgdHlwZTogW1wiUm9vdFwiXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBldmVudE5hbWU6IFtcIlBhc3N3b3JkUmVjb3ZlcnlSZXF1ZXN0ZWRcIl0sXG4gICAgICAgICAgICBldmVudFR5cGU6IFtcIkF3c0NvbnNvbGVTaWduSW5cIl0sXG4gICAgICAgICAgICByZXNwb25zZUVsZW1lbnRzOiB7XG4gICAgICAgICAgICAgIFBhc3N3b3JkUmVjb3ZlcnlSZXF1ZXN0ZWQ6IFtcIlN1Y2Nlc3NcIl0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KVxuXG4gICAgICAvLyBUcmlnZ2VyZWQgd2hlbiBwYXNzd29yZCBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgcmVzZXRcbiAgICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCBcIlJ1bGVGb3JSb290VXNlclBhc3N3b3JkUmVjb3ZlcnlDb21wbGV0ZVwiLCB7XG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICAgIHRhcmdldHM6IFtuZXcgdGFyZ2V0cy5MYW1iZGFGdW5jdGlvbihldmVudFRyYW5zZm9ybWVyKV0sXG4gICAgICAgIGV2ZW50UGF0dGVybjoge1xuICAgICAgICAgIGRldGFpbDoge1xuICAgICAgICAgICAgdXNlcklkZW50aXR5OiB7XG4gICAgICAgICAgICAgIHR5cGU6IFtcIlJvb3RcIl0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZXZlbnROYW1lOiBbXCJQYXNzd29yZFJlY292ZXJ5Q29tcGxldGVkXCJdLFxuICAgICAgICAgICAgZXZlbnRUeXBlOiBbXCJBd3NDb25zb2xlU2lnbkluXCJdLFxuICAgICAgICAgICAgcmVzcG9uc2VFbGVtZW50czoge1xuICAgICAgICAgICAgICBQYXNzd29yZFJlY292ZXJ5Q29tcGxldGVkOiBbXCJTdWNjZXNzXCJdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { CloudTrailSlackIntegration, CloudTrailSlackIntegrationProps, } from "./cloudtrail-slack-integration";
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CloudTrailSlackIntegration = void 0;
|
|
4
|
-
var cloudtrail_slack_integration_1 = require("./cloudtrail-slack-integration");
|
|
5
|
-
Object.defineProperty(exports, "CloudTrailSlackIntegration", { enumerable: true, get: function () { return cloudtrail_slack_integration_1.CloudTrailSlackIntegration; } });
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xvdWR0cmFpbC1zbGFjay1pbnRlZ3JhdGlvbi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrRUFHdUM7QUFGckMsMElBQUEsMEJBQTBCLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQge1xuICBDbG91ZFRyYWlsU2xhY2tJbnRlZ3JhdGlvbixcbiAgQ2xvdWRUcmFpbFNsYWNrSW50ZWdyYXRpb25Qcm9wcyxcbn0gZnJvbSBcIi4vY2xvdWR0cmFpbC1zbGFjay1pbnRlZ3JhdGlvblwiXG4iXX0=
|