p6-cdk-s3-protector 0.0.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.
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.handler = handler;
7
+ exports.main = main;
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const client_s3_1 = require("@aws-sdk/client-s3");
11
+ const client_s3_control_1 = require("@aws-sdk/client-s3-control");
12
+ const client_sts_1 = require("@aws-sdk/client-sts");
13
+ const winston_1 = __importDefault(require("winston"));
14
+ // Configure the logger
15
+ const logger = winston_1.default.createLogger({
16
+ level: 'info',
17
+ format: winston_1.default.format.json(),
18
+ defaultMeta: { service: 'user-service' },
19
+ transports: [
20
+ new winston_1.default.transports.Console(),
21
+ ],
22
+ });
23
+ const s3Client = new client_s3_1.S3({});
24
+ const s3ControlClient = new client_s3_control_1.S3ControlClient({});
25
+ const stsClient = new client_sts_1.STSClient({});
26
+ function p6ShortCircuitShould(event) {
27
+ if (event.detail.requestParameters['x-amz-acl']) {
28
+ logger.info('ACL is currently %s', event.detail.requestParameters['x-amz-acl'][0]);
29
+ if (event.detail.requestParameters['x-amz-acl'][0] === 'private') {
30
+ logger.info('ACL is already private. Ending.');
31
+ return true;
32
+ }
33
+ }
34
+ return false;
35
+ }
36
+ function p6LoopPrevent(event) {
37
+ if (event.detail.errorCode || event.detail.errorMessage) {
38
+ logger.info('Previous API call resulted in an error. Ending');
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ async function p6S3BucketAclGet(event) {
44
+ try {
45
+ const bucketName = event.detail.requestParameters.bucketName;
46
+ logger.info('Describing the current ACL: s3://%s', bucketName);
47
+ const bucketAcl = await s3Client.getBucketAcl({ Bucket: bucketName });
48
+ logger.info(JSON.stringify(bucketAcl));
49
+ return bucketAcl;
50
+ }
51
+ catch (err) {
52
+ logger.error('Error was: {%s} Manual followup recommended', err);
53
+ return false;
54
+ }
55
+ }
56
+ function p6LogDeliveryPreserve(bucketAcl) {
57
+ let uriList = '';
58
+ const preserveLogDelivery = [];
59
+ for (const grant of bucketAcl.Grants || []) {
60
+ if (grant.Grantee?.URI) {
61
+ logger.info('Found Grant: %s', JSON.stringify(grant));
62
+ uriList += grant.Grantee.URI;
63
+ if (grant.Grantee.URI.includes('LogDelivery')) {
64
+ preserveLogDelivery.push(grant);
65
+ }
66
+ }
67
+ }
68
+ return [uriList, preserveLogDelivery];
69
+ }
70
+ function p6S3BucketAclViolation(uriList) {
71
+ if (uriList.includes('AllUsers') || uriList.includes('AuthenticatedUsers')) {
72
+ logger.info('Violation found. Grant ACL greater than Private');
73
+ return true;
74
+ }
75
+ logger.info('ACL is correctly already private');
76
+ return false;
77
+ }
78
+ async function p6S3BucketAclCorrect(bucketAcl, preserveLogDelivery) {
79
+ logger.info('Attempting Automatic Resolution');
80
+ try {
81
+ if (preserveLogDelivery) {
82
+ logger.info('ACL resetting ACL to LogDelivery');
83
+ logger.info('Preserve was: %s', JSON.stringify(preserveLogDelivery));
84
+ const aclString = {
85
+ Grants: preserveLogDelivery,
86
+ Owner: bucketAcl.Owner,
87
+ };
88
+ const response = await s3Client.putBucketAcl({
89
+ Bucket: bucketAcl?.Owner?.ID,
90
+ AccessControlPolicy: aclString,
91
+ });
92
+ logger.info(JSON.stringify(response));
93
+ if (response.$metadata.httpStatusCode === 200) {
94
+ logger.info('Reverted to only contain LogDelivery');
95
+ }
96
+ else {
97
+ logger.error('PutBucketACL failed. Manual followup');
98
+ }
99
+ }
100
+ else {
101
+ logger.info('ACL resetting ACL to Private');
102
+ const response = await s3Client.putBucketAcl({
103
+ Bucket: bucketAcl?.Owner?.ID,
104
+ ACL: 'private',
105
+ });
106
+ logger.info(JSON.stringify(response));
107
+ if (response.$metadata.httpStatusCode === 200) {
108
+ logger.info('Bucket ACL has been changed to Private');
109
+ }
110
+ else {
111
+ logger.error('PutBucketACL failed. Manual followup');
112
+ }
113
+ }
114
+ }
115
+ catch (err) {
116
+ logger.info('Unable to resolve violation automatically');
117
+ logger.info('Error was: %s', err);
118
+ }
119
+ }
120
+ async function p6S3PublicBucketAcl(event) {
121
+ if (p6ShortCircuitShould(event)) {
122
+ return true;
123
+ }
124
+ if (p6LoopPrevent(event)) {
125
+ return true;
126
+ }
127
+ const bucketAcl = await p6S3BucketAclGet(event);
128
+ if (!bucketAcl) {
129
+ return false;
130
+ }
131
+ const [uriList, preserveLogDelivery] = p6LogDeliveryPreserve(bucketAcl);
132
+ if (p6S3BucketAclViolation(uriList)) {
133
+ await p6S3BucketAclCorrect(bucketAcl, preserveLogDelivery);
134
+ return true;
135
+ }
136
+ return false;
137
+ }
138
+ async function awsIsPrivate(bucket, key) {
139
+ logger.info('Describing the ACL: s3://%s/%s', bucket, key);
140
+ const acl = await s3Client.getObjectAcl({ Bucket: bucket, Key: key });
141
+ if (acl.Grants.length > 1) {
142
+ logger.info('Greater than one Grant');
143
+ return false;
144
+ }
145
+ const ownerId = acl.Owner?.ID;
146
+ const granteeId = acl.Grants[0].Grantee?.ID;
147
+ if (ownerId !== granteeId) {
148
+ logger.info('owner:[%s], grantee[%s] do not match', ownerId, granteeId);
149
+ return false;
150
+ }
151
+ return true;
152
+ }
153
+ async function awsMakePrivate(bucket, key) {
154
+ logger.info('Making s3://%s/%s private', bucket, key);
155
+ await s3Client.putObjectAcl({ Bucket: bucket, Key: key, ACL: 'private' });
156
+ }
157
+ async function p6S3PublicBucketObjectAcl(event) {
158
+ const key = event.detail.requestParameters.key;
159
+ const bucket = event.detail.requestParameters.bucketName;
160
+ if (!(await awsIsPrivate(bucket, key))) {
161
+ await awsMakePrivate(bucket, key);
162
+ }
163
+ }
164
+ async function p6S3PublicBucketAccessBlock(event) {
165
+ const pbc = event.detail.requestParameters.PublicAccessBlockConfiguration;
166
+ logger.info(JSON.stringify(pbc));
167
+ if (!pbc.RestrictPublicBuckets || !pbc.BlockPublicPolicy || !pbc.BlockPublicAcls || !pbc.IgnorePublicAcls) {
168
+ const bucket = event.detail.requestParameters.bucketName;
169
+ logger.info('s3://%s now not private, fixing...', bucket);
170
+ const response = await s3Client.putPublicAccessBlock({
171
+ Bucket: bucket,
172
+ PublicAccessBlockConfiguration: {
173
+ BlockPublicAcls: true,
174
+ IgnorePublicAcls: true,
175
+ BlockPublicPolicy: true,
176
+ RestrictPublicBuckets: true,
177
+ },
178
+ });
179
+ logger.info(JSON.stringify(response));
180
+ }
181
+ }
182
+ async function p6S3PublicAccessBlock(event) {
183
+ const pbc = event.detail.requestParameters.PublicAccessBlockConfiguration;
184
+ logger.info(JSON.stringify(pbc));
185
+ if (!pbc.RestrictPublicBuckets || !pbc.BlockPublicPolicy || !pbc.BlockPublicAcls || !pbc.IgnorePublicAcls) {
186
+ const command = new client_sts_1.GetCallerIdentityCommand({});
187
+ const account = await stsClient.send(command);
188
+ logger.info('%s', account);
189
+ const response = await s3ControlClient.send(new client_s3_control_1.PutPublicAccessBlockCommand({
190
+ PublicAccessBlockConfiguration: {
191
+ BlockPublicAcls: true,
192
+ IgnorePublicAcls: true,
193
+ BlockPublicPolicy: true,
194
+ RestrictPublicBuckets: true,
195
+ },
196
+ AccountId: account.Account,
197
+ }));
198
+ logger.info(JSON.stringify(response));
199
+ }
200
+ }
201
+ async function p6S3PublicFusebox(event) {
202
+ if (!event.detail || !event.detail.eventName) {
203
+ return false;
204
+ }
205
+ const events = [
206
+ 'PutBucketAcl',
207
+ 'PutObjectAcl',
208
+ 'PutBucketPublicAccessBlock',
209
+ 'PutAccountPublicAccessBlock',
210
+ ];
211
+ const eventName = event.detail.eventName;
212
+ if (events.includes(eventName)) {
213
+ logger.info('======================================================================================');
214
+ logger.info('eventName: %s', eventName);
215
+ }
216
+ if (eventName === 'PutBucketAcl') {
217
+ await p6S3PublicBucketAcl(event);
218
+ }
219
+ else if (eventName === 'PutObjectAcl') {
220
+ await p6S3PublicBucketObjectAcl(event);
221
+ }
222
+ else if (eventName === 'PutBucketPublicAccessBlock') {
223
+ await p6S3PublicBucketAccessBlock(event);
224
+ }
225
+ else if (eventName === 'PutAccountPublicAccessBlock') {
226
+ await p6S3PublicAccessBlock(event);
227
+ }
228
+ return true;
229
+ }
230
+ async function handler(event, _context) {
231
+ await p6S3PublicFusebox(event);
232
+ return true;
233
+ }
234
+ async function main() {
235
+ logger.debug('Reading fixtures/putBucketAcl.json');
236
+ const data = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.resolve('fixtures/putBucketAcl.json'), 'utf8'));
237
+ logger.debug('handler()');
238
+ await handler(data);
239
+ }
240
+ if (require.main === module) {
241
+ main();
242
+ }
243
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicDZjZGtzM3Byb3RlY3Rvci5wNkNES1MzUHJvdGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3A2Y2RrczNwcm90ZWN0b3IucDZDREtTM1Byb3RlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQXFSQSwwQkFHQztBQUVELG9CQU1DO0FBN1JELHNEQUF3QjtBQUN4QiwwREFBNEI7QUFDNUIsa0RBQXVDO0FBQ3ZDLGtFQUF5RjtBQUN6RixvREFBeUU7QUFDekUsc0RBQTZCO0FBRTdCLHVCQUF1QjtBQUN2QixNQUFNLE1BQU0sR0FBVyxpQkFBTyxDQUFDLFlBQVksQ0FBQztJQUMxQyxLQUFLLEVBQUUsTUFBTTtJQUNiLE1BQU0sRUFBRSxpQkFBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUU7SUFDN0IsV0FBVyxFQUFFLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRTtJQUN4QyxVQUFVLEVBQUU7UUFDVixJQUFJLGlCQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRTtLQUNqQztDQUNGLENBQUMsQ0FBQTtBQUVGLE1BQU0sUUFBUSxHQUFHLElBQUksY0FBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQzNCLE1BQU0sZUFBZSxHQUFHLElBQUksbUNBQWUsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUMvQyxNQUFNLFNBQVMsR0FBRyxJQUFJLHNCQUFTLENBQUMsRUFBRSxDQUFDLENBQUE7QUFhbkMsU0FBUyxvQkFBb0IsQ0FBQyxLQUFjO0lBQzFDLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1FBQ2hELE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ2xGLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxXQUFX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QUksS0FBSyxNQUFNLEVBQUUsQ0FBQztJQUM1QixJQUFJLEVBQUUsQ0FBQTtBQUNSLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEdldEJ1Y2tldEFjbE91dHB1dCwgR3JhbnQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtczMnXG5pbXBvcnQgdHlwZSB7IENvbnRleHQgfSBmcm9tICdhd3MtbGFtYmRhJ1xuaW1wb3J0IHR5cGUgeyBMb2dnZXIgfSBmcm9tICd3aW5zdG9uJ1xuaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMnXG5pbXBvcnQgcGF0aCBmcm9tICdub2RlOnBhdGgnXG5pbXBvcnQgeyBTMyB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zMydcbmltcG9ydCB7IFB1dFB1YmxpY0FjY2Vzc0Jsb2NrQ29tbWFuZCwgUzNDb250cm9sQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXMzLWNvbnRyb2wnXG5pbXBvcnQgeyBHZXRDYWxsZXJJZGVudGl0eUNvbW1hbmQsIFNUU0NsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zdHMnXG5pbXBvcnQgd2luc3RvbiBmcm9tICd3aW5zdG9uJ1xuXG4vLyBDb25maWd1cmUgdGhlIGxvZ2dlclxuY29uc3QgbG9nZ2VyOiBMb2dnZXIgPSB3aW5zdG9uLmNyZWF0ZUxvZ2dlcih7XG4gIGxldmVsOiAnaW5mbycsXG4gIGZvcm1hdDogd2luc3Rvbi5mb3JtYXQuanNvbigpLFxuICBkZWZhdWx0TWV0YTogeyBzZXJ2aWNlOiAndXNlci1zZXJ2aWNlJyB9LFxuICB0cmFuc3BvcnRzOiBbXG4gICAgbmV3IHdpbnN0b24udHJhbnNwb3J0cy5Db25zb2xlKCksXG4gIF0sXG59KVxuXG5jb25zdCBzM0NsaWVudCA9IG5ldyBTMyh7fSlcbmNvbnN0IHMzQ29udHJvbENsaWVudCA9IG5ldyBTM0NvbnRyb2xDbGllbnQoe30pXG5jb25zdCBzdHNDbGllbnQgPSBuZXcgU1RTQ2xpZW50KHt9KVxuXG5pbnRlcmZhY2UgUzNFdmVudCB7XG4gIGRldGFpbDoge1xuICAgIHJlcXVlc3RQYXJhbWV0ZXJzOiB7XG4gICAgICBba2V5OiBzdHJpbmddOiBhbnlcbiAgICB9XG4gICAgZXZlbnROYW1lOiBzdHJpbmdcbiAgICBlcnJvckNvZGU/OiBzdHJpbmdcbiAgICBlcnJvck1lc3NhZ2U/OiBzdHJpbmdcbiAgfVxufVxuXG5mdW5jdGlvbiBwNlNob3J0Q2lyY3VpdFNob3VsZChldmVudDogUzNFdmVudCk6IGJvb2xlYW4ge1xuICBpZiAoZXZlbnQuZGV0YWlsLnJlcXVlc3RQYXJhbWV0ZXJzWyd4LWFtei1hY2wnXSkge1xuICAgIGxvZ2dlci5pbmZvKCdBQ0wgaXMgY3VycmVudGx5ICVzJywgZXZlbnQuZGV0YWlsLnJlcXVlc3RQYXJhbWV0ZXJzWyd4LWFtei1hY2wnXVswXSlcbiAgICBpZiAoZXZlbnQuZGV0YWlsLnJlcXVlc3RQYXJhbWV0ZXJzWyd4LWFtei1hY2wnXVswXSA9PT0gJ3ByaXZhdGUnKSB7XG4gICAgICBsb2dnZXIuaW5mbygnQUNMIGlzIGFscmVhZHkgcHJpdmF0ZS4gIEVuZGluZy4nKVxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlXG59XG5cbmZ1bmN0aW9uIHA2TG9vcFByZXZlbnQoZXZlbnQ6IFMzRXZlbnQpOiBib29sZWFuIHtcbiAgaWYgKGV2ZW50LmRldGFpbC5lcnJvckNvZGUgfHwgZXZlbnQuZGV0YWlsLmVycm9yTWVzc2FnZSkge1xuICAgIGxvZ2dlci5pbmZvKCdQcmV2aW91cyBBUEkgY2FsbCByZXN1bHRlZCBpbiBhbiBlcnJvci4gRW5kaW5nJylcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG4gIHJldHVybiBmYWxzZVxufVxuXG5hc3luYyBmdW5jdGlvbiBwNlMzQnVja2V0QWNsR2V0KGV2ZW50OiBTM0V2ZW50KTogUHJvbWlzZTxHZXRCdWNrZXRBY2xPdXRwdXQgfCBmYWxzZT4ge1xuICB0cnkge1xuICAgIGNvbnN0IGJ1Y2tldE5hbWUgPSBldmVudC5kZXRhaWwucmVxdWVzdFBhcmFtZXRlcnMuYnVja2V0TmFtZVxuICAgIGxvZ2dlci5pbmZvKCdEZXNjcmliaW5nIHRoZSBjdXJyZW50IEFDTDogczM6Ly8lcycsIGJ1Y2tldE5hbWUpXG4gICAgY29uc3QgYnVja2V0QWNsID0gYXdhaXQgczNDbGllbnQuZ2V0QnVja2V0QWNsKHsgQnVja2V0OiBidWNrZXROYW1lIH0pXG4gICAgbG9nZ2VyLmluZm8oSlNPTi5zdHJpbmdpZnkoYnVja2V0QWNsKSlcbiAgICByZXR1cm4gYnVja2V0QWNsXG4gIH1cbiAgY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5lcnJvcignRXJyb3Igd2FzOiB7JXN9IE1hbnVhbCBmb2xsb3d1cCByZWNvbW1lbmRlZCcsIGVycilcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5mdW5jdGlvbiBwNkxvZ0RlbGl2ZXJ5UHJlc2VydmUoYnVja2V0QWNsOiBHZXRCdWNrZXRBY2xPdXRwdXQpOiBbc3RyaW5nLCBHcmFudFtdXSB7XG4gIGxldCB1cmlMaXN0ID0gJydcbiAgY29uc3QgcHJlc2VydmVMb2dEZWxpdmVyeTogR3JhbnRbXSA9IFtdXG5cbiAgZm9yIChjb25zdCBncmFudCBvZiBidWNrZXRBY2wuR3JhbnRzIHx8IFtdKSB7XG4gICAgaWYgKGdyYW50LkdyYW50ZWU/LlVSSSkge1xuICAgICAgbG9nZ2VyLmluZm8oJ0ZvdW5kIEdyYW50OiAlcycsIEpTT04uc3RyaW5naWZ5KGdyYW50KSlcbiAgICAgIHVyaUxpc3QgKz0gZ3JhbnQuR3JhbnRlZS5VUklcbiAgICAgIGlmIChncmFudC5HcmFudGVlLlVSSS5pbmNsdWRlcygnTG9nRGVsaXZlcnknKSkge1xuICAgICAgICBwcmVzZXJ2ZUxvZ0RlbGl2ZXJ5LnB1c2goZ3JhbnQpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIFt1cmlMaXN0LCBwcmVzZXJ2ZUxvZ0RlbGl2ZXJ5XVxufVxuXG5mdW5jdGlvbiBwNlMzQnVja2V0QWNsVmlvbGF0aW9uKHVyaUxpc3Q6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBpZiAodXJpTGlzdC5pbmNsdWRlcygnQWxsVXNlcnMnKSB8fCB1cmlMaXN0LmluY2x1ZGVzKCdBdXRoZW50aWNhdGVkVXNlcnMnKSkge1xuICAgIGxvZ2dlci5pbmZvKCdWaW9sYXRpb24gZm91bmQuICBHcmFudCBBQ0wgZ3JlYXRlciB0aGFuIFByaXZhdGUnKVxuICAgIHJldHVybiB0cnVlXG4gIH1cbiAgbG9nZ2VyLmluZm8oJ0FDTCBpcyBjb3JyZWN0bHkgYWxyZWFkeSBwcml2YXRlJylcbiAgcmV0dXJuIGZhbHNlXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHA2UzNCdWNrZXRBY2xDb3JyZWN0KGJ1Y2tldEFjbDogR2V0QnVja2V0QWNsT3V0cHV0LCBwcmVzZXJ2ZUxvZ0RlbGl2ZXJ5OiBBcnJheTxHcmFudD4gfCBmYWxzZSk6IFByb21pc2U8dm9pZD4ge1xuICBsb2dnZXIuaW5mbygnQXR0ZW1wdGluZyBBdXRvbWF0aWMgUmVzb2x1dGlvbicpXG4gIHRyeSB7XG4gICAgaWYgKHByZXNlcnZlTG9nRGVsaXZlcnkpIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdBQ0wgcmVzZXR0aW5nIEFDTCB0byBMb2dEZWxpdmVyeScpXG4gICAgICBsb2dnZXIuaW5mbygnUHJlc2VydmUgd2FzOiAlcycsIEpTT04uc3RyaW5naWZ5KHByZXNlcnZlTG9nRGVsaXZlcnkpKVxuXG4gICAgICBjb25zdCBhY2xTdHJpbmcgPSB7XG4gICAgICAgIEdyYW50czogcHJlc2VydmVMb2dEZWxpdmVyeSxcbiAgICAgICAgT3duZXI6IGJ1Y2tldEFjbC5Pd25lcixcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzM0NsaWVudC5wdXRCdWNrZXRBY2woe1xuICAgICAgICBCdWNrZXQ6IGJ1Y2tldEFjbD8uT3duZXI/LklELFxuICAgICAgICBBY2Nlc3NDb250cm9sUG9saWN5OiBhY2xTdHJpbmcsXG4gICAgICB9KVxuXG4gICAgICBsb2dnZXIuaW5mbyhKU09OLnN0cmluZ2lmeShyZXNwb25zZSkpXG4gICAgICBpZiAocmVzcG9uc2UuJG1ldGFkYXRhLmh0dHBTdGF0dXNDb2RlID09PSAyMDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1JldmVydGVkIHRvIG9ubHkgY29udGFpbiBMb2dEZWxpdmVyeScpXG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdQdXRCdWNrZXRBQ0wgZmFpbGVkLiBNYW51YWwgZm9sbG93dXAnKVxuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdBQ0wgcmVzZXR0aW5nIEFDTCB0byBQcml2YXRlJylcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgczNDbGllbnQucHV0QnVja2V0QWNsKHtcbiAgICAgICAgQnVja2V0OiBidWNrZXRBY2w/Lk93bmVyPy5JRCxcbiAgICAgICAgQUNMOiAncHJpdmF0ZScsXG4gICAgICB9KVxuXG4gICAgICBsb2dnZXIuaW5mbyhKU09OLnN0cmluZ2lmeShyZXNwb25zZSkpXG4gICAgICBpZiAocmVzcG9uc2UuJG1ldGFkYXRhLmh0dHBTdGF0dXNDb2RlID09PSAyMDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ0J1Y2tldCBBQ0wgaGFzIGJlZW4gY2hhbmdlZCB0byBQcml2YXRlJylcbiAgICAgIH1cbiAgICAgIGVsc2Uge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ1B1dEJ1Y2tldEFDTCBmYWlsZWQuIE1hbnVhbCBmb2xsb3d1cCcpXG4gICAgICB9XG4gICAgfVxuICB9XG4gIGNhdGNoIChlcnIpIHtcbiAgICBsb2dnZXIuaW5mbygnVW5hYmxlIHRvIHJlc29sdmUgdmlvbGF0aW9uIGF1dG9tYXRpY2FsbHknKVxuICAgIGxvZ2dlci5pbmZvKCdFcnJvciB3YXM6ICVzJywgZXJyKVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHA2UzNQdWJsaWNCdWNrZXRBY2woZXZlbnQ6IFMzRXZlbnQpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgaWYgKHA2U2hvcnRDaXJjdWl0U2hvdWxkKGV2ZW50KSkge1xuICAgIHJldHVybiB0cnVlXG4gIH1cblxuICBpZiAocDZMb29wUHJldmVudChldmVudCkpIHtcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgY29uc3QgYnVja2V0QWNsID0gYXdhaXQgcDZTM0J1Y2tldEFjbEdldChldmVudClcbiAgaWYgKCFidWNrZXRBY2wpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGNvbnN0IFt1cmlMaXN0LCBwcmVzZXJ2ZUxvZ0RlbGl2ZXJ5XSA9IHA2TG9nRGVsaXZlcnlQcmVzZXJ2ZShidWNrZXRBY2wpXG5cbiAgaWYgKHA2UzNCdWNrZXRBY2xWaW9sYXRpb24odXJpTGlzdCkpIHtcbiAgICBhd2FpdCBwNlMzQnVja2V0QWNsQ29ycmVjdChidWNrZXRBY2wsIHByZXNlcnZlTG9nRGVsaXZlcnkpXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIHJldHVybiBmYWxzZVxufVxuXG5hc3luYyBmdW5jdGlvbiBhd3NJc1ByaXZhdGUoYnVja2V0OiBzdHJpbmcsIGtleTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGxvZ2dlci5pbmZvKCdEZXNjcmliaW5nIHRoZSBBQ0w6IHMzOi8vJXMvJXMnLCBidWNrZXQsIGtleSlcbiAgY29uc3QgYWNsID0gYXdhaXQgczNDbGllbnQuZ2V0T2JqZWN0QWNsKHsgQnVja2V0OiBidWNrZXQsIEtleToga2V5IH0pXG5cbiAgaWYgKGFjbC5HcmFudHMhLmxlbmd0aCA+IDEpIHtcbiAgICBsb2dnZXIuaW5mbygnR3JlYXRlciB0aGFuIG9uZSBHcmFudCcpXG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICBjb25zdCBvd25lcklkID0gYWNsLk93bmVyPy5JRFxuICBjb25zdCBncmFudGVlSWQgPSBhY2wuR3JhbnRzIVswXS5HcmFudGVlPy5JRFxuICBpZiAob3duZXJJZCAhPT0gZ3JhbnRlZUlkKSB7XG4gICAgbG9nZ2VyLmluZm8oJ293bmVyOlslc10sIGdyYW50ZWVbJXNdIGRvIG5vdCBtYXRjaCcsIG93bmVySWQsIGdyYW50ZWVJZClcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIHJldHVybiB0cnVlXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGF3c01ha2VQcml2YXRlKGJ1Y2tldDogc3RyaW5nLCBrZXk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBsb2dnZXIuaW5mbygnTWFraW5nIHMzOi8vJXMvJXMgcHJpdmF0ZScsIGJ1Y2tldCwga2V5KVxuICBhd2FpdCBzM0NsaWVudC5wdXRPYmplY3RBY2woeyBCdWNrZXQ6IGJ1Y2tldCwgS2V5OiBrZXksIEFDTDogJ3ByaXZhdGUnIH0pXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHA2UzNQdWJsaWNCdWNrZXRPYmplY3RBY2woZXZlbnQ6IFMzRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qga2V5ID0gZXZlbnQuZGV0YWlsLnJlcXVlc3RQYXJhbWV0ZXJzLmtleVxuICBjb25zdCBidWNrZXQgPSBldmVudC5kZXRhaWwucmVxdWVzdFBhcmFtZXRlcnMuYnVja2V0TmFtZVxuXG4gIGlmICghKGF3YWl0IGF3c0lzUHJpdmF0ZShidWNrZXQsIGtleSkpKSB7XG4gICAgYXdhaXQgYXdzTWFrZVByaXZhdGUoYnVja2V0LCBrZXkpXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcDZTM1B1YmxpY0J1Y2tldEFjY2Vzc0Jsb2NrKGV2ZW50OiBTM0V2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHBiYyA9IGV2ZW50LmRldGFpbC5yZXF1ZXN0UGFyYW1ldGVycy5QdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb25cbiAgbG9nZ2VyLmluZm8oSlNPTi5zdHJpbmdpZnkocGJjKSlcblxuICBpZiAoIXBiYy5SZXN0cmljdFB1YmxpY0J1Y2tldHMgfHwgIXBiYy5CbG9ja1B1YmxpY1BvbGljeSB8fCAhcGJjLkJsb2NrUHVibGljQWNscyB8fCAhcGJjLklnbm9yZVB1YmxpY0FjbHMpIHtcbiAgICBjb25zdCBidWNrZXQgPSBldmVudC5kZXRhaWwucmVxdWVzdFBhcmFtZXRlcnMuYnVja2V0TmFtZVxuICAgIGxvZ2dlci5pbmZvKCdzMzovLyVzIG5vdyBub3QgcHJpdmF0ZSwgZml4aW5nLi4uJywgYnVja2V0KVxuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzM0NsaWVudC5wdXRQdWJsaWNBY2Nlc3NCbG9jayh7XG4gICAgICBCdWNrZXQ6IGJ1Y2tldCxcbiAgICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBCbG9ja1B1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgIElnbm9yZVB1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWUsXG4gICAgICB9LFxuICAgIH0pXG5cbiAgICBsb2dnZXIuaW5mbyhKU09OLnN0cmluZ2lmeShyZXNwb25zZSkpXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcDZTM1B1YmxpY0FjY2Vzc0Jsb2NrKGV2ZW50OiBTM0V2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHBiYyA9IGV2ZW50LmRldGFpbC5yZXF1ZXN0UGFyYW1ldGVycy5QdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb25cbiAgbG9nZ2VyLmluZm8oSlNPTi5zdHJpbmdpZnkocGJjKSlcblxuICBpZiAoIXBiYy5SZXN0cmljdFB1YmxpY0J1Y2tldHMgfHwgIXBiYy5CbG9ja1B1YmxpY1BvbGljeSB8fCAhcGJjLkJsb2NrUHVibGljQWNscyB8fCAhcGJjLklnbm9yZVB1YmxpY0FjbHMpIHtcbiAgICBjb25zdCBjb21tYW5kID0gbmV3IEdldENhbGxlcklkZW50aXR5Q29tbWFuZCh7fSlcbiAgICBjb25zdCBhY2NvdW50ID0gYXdhaXQgc3RzQ2xpZW50LnNlbmQoY29tbWFuZClcbiAgICBsb2dnZXIuaW5mbygnJXMnLCBhY2NvdW50KVxuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBzM0NvbnRyb2xDbGllbnQuc2VuZChuZXcgUHV0UHVibGljQWNjZXNzQmxvY2tDb21tYW5kKHtcbiAgICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBCbG9ja1B1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgIElnbm9yZVB1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWUsXG4gICAgICB9LFxuICAgICAgQWNjb3VudElkOiBhY2NvdW50LkFjY291bnQsXG4gICAgfSkpXG5cbiAgICBsb2dnZXIuaW5mbyhKU09OLnN0cmluZ2lmeShyZXNwb25zZSkpXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcDZTM1B1YmxpY0Z1c2Vib3goZXZlbnQ6IFMzRXZlbnQpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgaWYgKCFldmVudC5kZXRhaWwgfHwgIWV2ZW50LmRldGFpbC5ldmVudE5hbWUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGNvbnN0IGV2ZW50cyA9IFtcbiAgICAnUHV0QnVja2V0QWNsJyxcbiAgICAnUHV0T2JqZWN0QWNsJyxcbiAgICAnUHV0QnVja2V0UHVibGljQWNjZXNzQmxvY2snLFxuICAgICdQdXRBY2NvdW50UHVibGljQWNjZXNzQmxvY2snLFxuICBdXG5cbiAgY29uc3QgZXZlbnROYW1lID0gZXZlbnQuZGV0YWlsLmV2ZW50TmFtZVxuICBpZiAoZXZlbnRzLmluY2x1ZGVzKGV2ZW50TmFtZSkpIHtcbiAgICBsb2dnZXIuaW5mbygnPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0nKVxuICAgIGxvZ2dlci5pbmZvKCdldmVudE5hbWU6ICVzJywgZXZlbnROYW1lKVxuICB9XG5cbiAgaWYgKGV2ZW50TmFtZSA9PT0gJ1B1dEJ1Y2tldEFjbCcpIHtcbiAgICBhd2FpdCBwNlMzUHVibGljQnVja2V0QWNsKGV2ZW50KVxuICB9XG4gIGVsc2UgaWYgKGV2ZW50TmFtZSA9PT0gJ1B1dE9iamVjdEFjbCcpIHtcbiAgICBhd2FpdCBwNlMzUHVibGljQnVja2V0T2JqZWN0QWNsKGV2ZW50KVxuICB9XG4gIGVsc2UgaWYgKGV2ZW50TmFtZSA9PT0gJ1B1dEJ1Y2tldFB1YmxpY0FjY2Vzc0Jsb2NrJykge1xuICAgIGF3YWl0IHA2UzNQdWJsaWNCdWNrZXRBY2Nlc3NCbG9jayhldmVudClcbiAgfVxuICBlbHNlIGlmIChldmVudE5hbWUgPT09ICdQdXRBY2NvdW50UHVibGljQWNjZXNzQmxvY2snKSB7XG4gICAgYXdhaXQgcDZTM1B1YmxpY0FjY2Vzc0Jsb2NrKGV2ZW50KVxuICB9XG5cbiAgcmV0dXJuIHRydWVcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IFMzRXZlbnQsIF9jb250ZXh0PzogQ29udGV4dCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBhd2FpdCBwNlMzUHVibGljRnVzZWJveChldmVudClcbiAgcmV0dXJuIHRydWVcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gIGxvZ2dlci5kZWJ1ZygnUmVhZGluZyBmaXh0dXJlcy9wdXRCdWNrZXRBY2wuanNvbicpXG4gIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhwYXRoLnJlc29sdmUoJ2ZpeHR1cmVzL3B1dEJ1Y2tldEFjbC5qc29uJyksICd1dGY4JykpXG5cbiAgbG9nZ2VyLmRlYnVnKCdoYW5kbGVyKCknKVxuICBhd2FpdCBoYW5kbGVyKGRhdGEpXG59XG5cbmlmIChyZXF1aXJlLm1haW4gPT09IG1vZHVsZSkge1xuICBtYWluKClcbn1cbiJdfQ==
package/package.json ADDED
@@ -0,0 +1,141 @@
1
+ {
2
+ "name": "p6-cdk-s3-protector",
3
+ "description": "AWS CDK: S3 a real-time protector",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/p6m7g8/p6-cdk-s3-protector.git"
7
+ },
8
+ "scripts": {
9
+ "act:build": "act --container-architecture linux/amd64 --container-daemon-socket - --container-options \"--memory 4g\" -j build",
10
+ "act:release": "act --container-architecture linux/amd64 --container-daemon-socket - --container-options \"--memory 4g\" -j release",
11
+ "build": "pnpm run ci:local && pnpm run jsii:pacmak:parallel",
12
+ "ci:both": "pnpm run compile && pnpm run lint && pnpm run jsii:docgen && pnpm run test",
13
+ "ci:gha": "pnpm run ci:both",
14
+ "ci:local": "pnpm run ci:both && pnpm run diagram:update",
15
+ "clean": "rm -rf dist/ lib/ cdk.out/ coverage/ .jsii",
16
+ "compile": "pnpm run tsc:compile && pnpm run jsii:compile",
17
+ "diagram:run": "pnpm run diagram:update && pnpm run diagram:serve",
18
+ "diagram:update": "pnpm run synth && pnpm run diagram:png && pnpm run diagram:cytoscape",
19
+ "diagram:cytoscape": "pnpm cdk-dia --target-path assets --rendering cytoscape-html -- ts-node bin/visualize.ts",
20
+ "diagram:png": "pnpm cdk-dia --target-path assets/diagram.png -- ts-node bin/visualize.ts",
21
+ "diagram:serve": "pnpm http-server assets -o",
22
+ "jsii:compile": "pnpm jsii compile --verbose -c tsconfig.dev.json",
23
+ "jsii:docgen": "pnpm jsii-docgen -v -o API.md",
24
+ "jsii:pacmak:dotnet": "pnpm jsii-pacmak --verbose --targets dotnet",
25
+ "jsii:pacmak:go": "pnpm jsii-pacmak --verbose --targets go",
26
+ "jsii:pacmak:java": "pnpm jsii-pacmak --verbose --targets java",
27
+ "jsii:pacmak:js": "pnpm jsii-pacmak --verbose --targets js",
28
+ "jsii:pacmak:parallel": "pnpm jsii-pacmak --verbose --parallel --targets dotnet,go,java,js,python",
29
+ "jsii:pacmak:py": "pnpm jsii-pacmak --verbose --targets python",
30
+ "lint:fix": "pnpm eslint . --fix",
31
+ "lint": "pnpm eslint .",
32
+ "nuke": "pnpm run clean && rm -rf node_modules/",
33
+ "publish": "pnpm run build && pnpm run publish:npm && pnpm run publish:pypi && pnpm run publish:maven && pnpm run publish:nuget && pnpm run publish:golang",
34
+ "publish:nuget": "pnpm publib-nuget",
35
+ "publish:golang": "pnpm publib-golang",
36
+ "publish:maven": "pnpm publib-maven",
37
+ "publish:npm": "pnpm publib-npm",
38
+ "publish:pypi": "pnpm publib-pypi",
39
+ "reset": "pnpm run nuke && rm -f pnpm-lock.yaml",
40
+ "synth": "pnpm cdk synth",
41
+ "test": "node --max-old-space-size=4096 --trace-deprecation ./node_modules/jest/bin/jest.js --config jest.config.js --coverage --updateSnapshot",
42
+ "test:watch": "node --max-old-space-size=4096 --trace-deprecation ./node_modules/jest/bin/jest.js --config jest.config.js --watch --coverage --updateSnapshot",
43
+ "tsc:compile": "pnpm tsc -p tsconfig.dev.json"
44
+ },
45
+ "author": {
46
+ "name": "Philip M. Gollucci",
47
+ "email": "pgollucci@p6m7g8.com",
48
+ "organization": true
49
+ },
50
+ "devDependencies": {
51
+ "@antfu/eslint-config": "^3.8.0",
52
+ "@swc-node/register": "^1.10.9",
53
+ "@types/aws-lambda": "^8.10.145",
54
+ "@types/jest": "^29.5.14",
55
+ "@types/node": "22.8.2",
56
+ "@typescript-eslint/eslint-plugin": "^8.12.0",
57
+ "@typescript-eslint/parser": "^8.12.0",
58
+ "aws-cdk": "^2.164.1",
59
+ "aws-cdk-lib": "2.164.1",
60
+ "cdk-dia": "^0.11.0",
61
+ "constructs": "10.4.2",
62
+ "esbuild": "^0.24.0",
63
+ "eslint": "^9.13.0",
64
+ "eslint-plugin-import": "^2.31.0",
65
+ "http-server": "^14.1.1",
66
+ "jest": "^29.7.0",
67
+ "jsii": "^5.5.4",
68
+ "jsii-diff": "^1.104.0",
69
+ "jsii-docgen": "^10.5.5",
70
+ "jsii-pacmak": "^1.104.0",
71
+ "publib": "^0.2.906",
72
+ "ts-jest": "^29.2.5",
73
+ "ts-node": "^10.9.2",
74
+ "typescript": "~5.6.3"
75
+ },
76
+ "peerDependencies": {
77
+ "aws-cdk-lib": "2.164.1",
78
+ "constructs": "^10.4.2"
79
+ },
80
+ "dependencies": {
81
+ "@aws-sdk/client-s3": "^3.679.0",
82
+ "@aws-sdk/client-s3-control": "^3.679.0",
83
+ "@aws-sdk/client-sts": "^3.679.0",
84
+ "@types/aws-lambda": "^8.10.145",
85
+ "aws-cdk-lib": "2.164.1",
86
+ "aws-sdk": "^2.1691.0",
87
+ "cdk-iam-floyd": "^0.658.0",
88
+ "constructs": "^10.4.2",
89
+ "source-map-support": "^0.5.21",
90
+ "winston": "^3.15.0"
91
+ },
92
+ "bundledDependencies": [
93
+ "@aws-sdk/client-s3",
94
+ "@aws-sdk/client-s3-control",
95
+ "@aws-sdk/client-sts",
96
+ "@types/aws-lambda",
97
+ "aws-sdk",
98
+ "cdk-iam-floyd",
99
+ "source-map-support",
100
+ "winston"
101
+ ],
102
+ "keywords": [
103
+ "aws",
104
+ "cdk",
105
+ "s3",
106
+ "compliance",
107
+ "security"
108
+ ],
109
+ "main": "lib/index.js",
110
+ "types": "src/index.d.ts",
111
+ "license": "Apache-2.0",
112
+ "version": "0.0.1",
113
+ "jsii": {
114
+ "outdir": "dist",
115
+ "tsc": {
116
+ "outDir": "lib",
117
+ "rootDir": "src"
118
+ },
119
+ "targets": {
120
+ "java": {
121
+ "package": "com.github.p6m7g8.p6cds3protector",
122
+ "maven": {
123
+ "groupId": "com.github.p6m7g8",
124
+ "artifactId": "p6-cdk-s3-protector"
125
+ }
126
+ },
127
+ "python": {
128
+ "distName": "p6-cdk-s3-protector",
129
+ "module": "p6_cdk_s3_protector"
130
+ },
131
+ "dotnet": {
132
+ "namespace": "P6m7g8.P6CDKS3Protector",
133
+ "packageId": "P6m7g8.P6CDKS3Protector"
134
+ },
135
+ "go": {
136
+ "moduleName": "github.com/p6m7g8/p6-cdk-s3-protector"
137
+ }
138
+ }
139
+ },
140
+ "packageManager": "pnpm@9.12.2+sha512.22721b3a11f81661ae1ec68ce1a7b879425a1ca5b991c975b074ac220b187ce56c708fe5db69f4c962c989452eee76c82877f4ee80f474cebd61ee13461b6228"
141
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './p6cdks3protector'