Skip to content

Commit 3d9db6f

Browse files
authored
Merge pull request #2124 from AkhtarAmir/update-access-analyzer-active-finding-v2
Update access analyzer active findings v2
2 parents 8bb9b12 + 61009d0 commit 3d9db6f

6 files changed

Lines changed: 181 additions & 10 deletions

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
var AWS = require('aws-sdk');
2+
var async = require('async');
3+
var helpers = require(__dirname + '/../../../helpers/aws');
4+
5+
module.exports = function(AWSConfig, collection, retries, callback) {
6+
var accessanalyzer = new AWS.AccessAnalyzer(AWSConfig);
7+
async.eachLimit(collection.accessanalyzer.listAnalyzers[AWSConfig.region].data, 15, function(analyzer, cb) {
8+
collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn] = {};
9+
var params = {
10+
analyzerArn: analyzer.arn
11+
};
12+
13+
var paginating = false;
14+
var paginateCb = function(err, data) {
15+
if (err) collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn].err = err;
16+
17+
if (!data) return cb();
18+
19+
if (paginating && data.findings && data.findings.length &&
20+
collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn].data.findings &&
21+
collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn].data.findings.length) {
22+
collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn].data.findings = collection.accessanalyzer.listFindings[AWSConfig.region][analyzer.arn].data.findings.concat(data.findings);
23+
} else {
24+
collection.accessanalyzer.listFindingsV2[AWSConfig.region][analyzer.arn].data = data;
25+
}
26+
27+
if (data.nextToken && data.nextToken.length) {
28+
paginating = true;
29+
return execute(data.nextToken);
30+
}
31+
32+
cb();
33+
};
34+
35+
function execute(nextToken) { // eslint-disable-line no-inner-declarations
36+
var localParams = JSON.parse(JSON.stringify(params || {}));
37+
if (nextToken) localParams['nextToken'] = nextToken;
38+
if (nextToken) {
39+
helpers.makeCustomCollectorCall(accessanalyzer, 'listFindingsV2', localParams, retries, null, null, null, paginateCb);
40+
} else {
41+
helpers.makeCustomCollectorCall(accessanalyzer, 'listFindingsV2', params, retries, null, null, null, paginateCb);
42+
}
43+
}
44+
45+
execute();
46+
}, function(){
47+
callback();
48+
});
49+
};

helpers/aws/api.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1833,8 +1833,14 @@ var postcalls = [
18331833
reliesOnCall: 'listAnalyzers',
18341834
override: true
18351835
},
1836+
listFindingsV2: {
1837+
reliesOnService: 'accessanalyzer',
1838+
reliesOnCall: 'listAnalyzers',
1839+
override: true
1840+
},
18361841
sendIntegration: serviceMap['IAM'][0]
18371842
},
1843+
18381844
APIGateway: {
18391845
getStages: {
18401846
reliesOnService: 'apigateway',
@@ -2684,7 +2690,7 @@ var postcalls = [
26842690
reliesOnCall: 'listFunctions',
26852691
filterKey: 'FunctionName',
26862692
filterValue: 'FunctionName',
2687-
rateLimit: 100, // it's not documented but experimentially 10/second works.
2693+
rateLimit: 100, // it's not documented but experimental 10/second works.
26882694
},
26892695
getFunction: {
26902696
reliesOnService: 'lambda',

plugins/aws/accessanalyzer/accessAnalyzerActiveFindings.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
'You can view IAM Access Analyzer findings at any time. Work through all of the findings in your account until you have zero active findings.',
1212
link: 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-work-with-findings.html',
1313
recommended_action: 'Investigate into active findings in your account and do the needful until you have zero active findings.',
14-
apis: ['AccessAnalyzer:listAnalyzers', 'AccessAnalyzer:listFindings'],
14+
apis: ['AccessAnalyzer:listAnalyzers', 'AccessAnalyzer:listFindings', 'AccessAnalyzer:listFindingsV2'],
1515
realtime_triggers: ['accessanalyzer:CreateAnalyzer','accessanalyzer:DeleteAnalyzer','accessanalyzer:CreateArchiveRule','accessanalyzer:StartResourceScan'],
1616

1717
run: function(cache, settings, callback) {
@@ -40,19 +40,32 @@ module.exports = {
4040
if (!analyzer.arn) continue;
4141

4242
let resource = analyzer.arn;
43+
let totalFiltered = [];
4344

4445
var listFindings = helpers.addSource(cache, source,
4546
['accessanalyzer', 'listFindings', region, analyzer.arn]);
4647

47-
if (!listFindings || listFindings.err || !listFindings.data) {
48+
if (listFindings && !listFindings.err && listFindings.data) {
49+
let filtered = listFindings.data.findings.filter(finding => finding.status === 'ACTIVE');
50+
totalFiltered = totalFiltered.concat(filtered);
51+
}
52+
53+
var listFindingsV2 = helpers.addSource(cache, source,
54+
['accessanalyzer', 'listFindingsV2', region, analyzer.arn]);
55+
56+
if (listFindingsV2 && !listFindingsV2.err && listFindingsV2.data) {
57+
let filteredv2 = listFindingsV2.data.findings.filter(finding => finding.status === 'ACTIVE');
58+
totalFiltered = totalFiltered.concat(filteredv2);
59+
}
60+
61+
if ((!listFindings || listFindings.err || !listFindings.data) && (!listFindingsV2 || listFindingsV2.err || !listFindingsV2.data)) {
4862
helpers.addResult(results, 3,
49-
`Unable to IAM Access Analyzer findings: ${helpers.addError(listFindings)}`,
63+
`Unable to IAM Access Analyzer findings: ${helpers.addError(listFindings)} ${helpers.addError(listFindingsV2)}`,
5064
region, resource);
5165
continue;
5266
}
5367

54-
let filtered = listFindings.data.findings.filter(finding => finding.status === 'ACTIVE');
55-
if (!filtered.length) {
68+
if (!totalFiltered.length) {
5669
helpers.addResult(results, 0,
5770
'Amazon IAM Access Analyzer has no active findings',
5871
region, resource);

plugins/aws/accessanalyzer/accessAnalyzerActiveFindings.spec.js

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,83 @@ const listFindings = [
138138

139139
];
140140

141+
const listFindingsV2 = [
142+
{
143+
"findings": [
144+
{
145+
"analyzedAt": "2025-01-23T13:06:24+00:00",
146+
"createdAt": "2025-01-23T13:06:56+00:00",
147+
"id": "1a234567-bc6d-7yui-h5j7-4f5f9j8987y0",
148+
"resource": "arn:aws:iam::123456789123:role/abcd-abcd-adfitoui-abcdefg-p1-AsdfghTfjdudnjkDkjg-Z9JgMyMzcxOZ",
149+
"resourceType": "AWS::IAM::Role",
150+
"resourceOwnerAccount": "123456789123",
151+
"status": "ACTIVE",
152+
"updatedAt": "2025-01-23T13:06:56+00:00",
153+
"findingType": "UnusedIAMRole"
154+
},
155+
{
156+
"analyzedAt": "2025-01-23T13:06:24+00:00",
157+
"createdAt": "2025-01-23T13:06:56+00:00",
158+
"id": "938r4848-4h4j-8449-76d8-8768dh5dhh4u",
159+
"resource": "arn:aws:iam::123456789123:role/abcd-abcd-adfitoui-abcdefg-AsdfghTfjdudnjkDkjg-6vzrTVSqTaNe",
160+
"resourceType": "AWS::IAM::Role",
161+
"resourceOwnerAccount": "123456789123",
162+
"status": "ACTIVE",
163+
"updatedAt": "2025-01-23T13:06:56+00:00",
164+
"findingType": "UnusedIAMRole"
165+
},
166+
{
167+
"analyzedAt": "2025-01-23T13:06:55+00:00",
168+
"createdAt": "2025-01-23T13:06:56+00:00",
169+
"id": "7484f848-984j-498l-784s-yryh74748f45",
170+
"resource": "arn:aws:iam::123456789123:role/service-role/sdfghyFj-FGH-njkkjg-plgd-6uhjn9ok",
171+
"resourceType": "AWS::IAM::Role",
172+
"resourceOwnerAccount": "123456789123",
173+
"status": "ACTIVE",
174+
"updatedAt": "2025-01-23T13:06:56+00:00",
175+
"findingType": "UnusedPermission"
176+
},
177+
]
178+
},
179+
{
180+
"findings": [
181+
{
182+
"analyzedAt": "2025-01-23T13:06:24+00:00",
183+
"createdAt": "2025-01-23T13:06:56+00:00",
184+
"id": "1a234567-bc6d-7yui-h5j7-4f5f9j8987y0",
185+
"resource": "arn:aws:iam::123456789123:role/abcd-abcd-adfitoui-abcdefg-p1-AsdfghTfjdudnjkDkjg-Z9JgMyMzcxOZ",
186+
"resourceType": "AWS::IAM::Role",
187+
"resourceOwnerAccount": "123456789123",
188+
"status": "ARCHIVED",
189+
"updatedAt": "2025-01-23T13:06:56+00:00",
190+
"findingType": "UnusedIAMRole"
191+
},
192+
{
193+
"analyzedAt": "2025-01-23T13:06:24+00:00",
194+
"createdAt": "2025-01-23T13:06:56+00:00",
195+
"id": "938r4848-4h4j-8449-76d8-8768dh5dhh4u",
196+
"resource": "arn:aws:iam::123456789123:role/abcd-abcd-adfitoui-abcdefg-AsdfghTfjdudnjkDkjg-6vzrTVSqTaNe",
197+
"resourceType": "AWS::IAM::Role",
198+
"resourceOwnerAccount": "123456789123",
199+
"status": "ARCHIVED",
200+
"updatedAt": "2025-01-23T13:06:56+00:00",
201+
"findingType": "UnusedIAMRole"
202+
},
203+
{
204+
"analyzedAt": "2025-01-23T13:06:55+00:00",
205+
"createdAt": "2025-01-23T13:06:56+00:00",
206+
"id": "7484f848-984j-498l-784s-yryh74748f45",
207+
"resource": "arn:aws:iam::123456789123:role/service-role/sdfghyFj-FGH-njkkjg-plgd-6uhjn9ok",
208+
"resourceType": "AWS::IAM::Role",
209+
"resourceOwnerAccount": "123456789123",
210+
"status": "RESOLVED",
211+
"updatedAt": "2025-01-23T13:06:56+00:00",
212+
"findingType": "UnusedPermission"
213+
},
214+
]
215+
}
216+
217+
]
141218

142219
const createCache = (analyzer, listFindings, analyzerErr, listFindingsErr) => {
143220
var analyzerArn = (analyzer && analyzer.length) ? analyzer[0].arn: null;
@@ -163,7 +240,7 @@ const createCache = (analyzer, listFindings, analyzerErr, listFindingsErr) => {
163240

164241
describe('accessAnalyzerActiveFindings', function () {
165242
describe('run', function () {
166-
it('should FAIL if Amazon IAM access analyzer has active findings.', function (done) {
243+
it('should FAIL if Amazon IAM access analyzer V1 has active findings.', function (done) {
167244
const cache = createCache(listAnalyzers, listFindings[0]);
168245
accessAnalyzerActiveFindings.run(cache, {}, (err, results) => {
169246
expect(results.length).to.equal(1);
@@ -174,7 +251,18 @@ describe('accessAnalyzerActiveFindings', function () {
174251
});
175252
});
176253

177-
it('should PASS if Amazon IAM access analyzer have no active findings.', function (done) {
254+
it('should FAIL if Amazon IAM access analyzer v2 has active findings.', function (done) {
255+
const cache = createCache(listAnalyzers, listFindingsV2[0]);
256+
accessAnalyzerActiveFindings.run(cache, {}, (err, results) => {
257+
expect(results.length).to.equal(1);
258+
expect(results[0].status).to.equal(2);
259+
expect(results[0].region).to.equal('us-east-1');
260+
expect(results[0].message).to.include('Amazon IAM Access Analyzer has active findings');
261+
done();
262+
});
263+
});
264+
265+
it('should PASS if Amazon IAM access analyzer V1 have no active findings.', function (done) {
178266
const cache = createCache(listAnalyzers, listFindings[1]);
179267
accessAnalyzerActiveFindings.run(cache, {}, (err, results) => {
180268
expect(results.length).to.equal(1);
@@ -186,6 +274,19 @@ describe('accessAnalyzerActiveFindings', function () {
186274
});
187275
});
188276

277+
278+
it('should PASS if Amazon IAM access analyzer V2 have no active findings.', function (done) {
279+
const cache = createCache(listAnalyzers, listFindingsV2[1]);
280+
accessAnalyzerActiveFindings.run(cache, {}, (err, results) => {
281+
expect(results.length).to.equal(1);
282+
expect(results[0].status).to.equal(0);
283+
expect(results[0].region).to.equal('us-east-1');
284+
expect(results[0].message).to.include('Amazon IAM Access Analyzer has no active findings');
285+
286+
done();
287+
});
288+
});
289+
189290
it('should PASS if no analyzers found', function (done) {
190291
const cache = createCache([]);
191292
accessAnalyzerActiveFindings.run(cache, {}, (err, results) => {

plugins/azure/advisor/checkAdvisorRecommendations.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module.exports = {
88
severity: 'Medium',
99
description: 'Ensure that all Microsoft Azure Advisor recommendations found are implemented to optimize your cloud deployments, increase security, and reduce costs.',
1010
more_info: 'Advisor service analyzes your Azure cloud configurations and resource usage telemetry to provide personalized and actionable recommendations that can help you optimize your cloud resources for security, reliability and high availability, operational excellence, performance efficiency, and cost.',
11-
recommended_action: 'Implement all Microsoft Azurer Adivsor recommendations.',
11+
recommended_action: 'Implement all Microsoft Azurer Advisor recommendations.',
1212
link: 'https://learn.microsoft.com/en-us/azure/advisor/advisor-get-started',
1313
apis: ['advisor:recommendationsList'],
1414

plugins/azure/automationAccounts/automationAcctExpiredWebhooks.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var expect = require('chai').expect;
22
var automationAcctExpiredWebhooks = require('./automationAcctExpiredWebhooks');
3+
var nextMonthExpiry = new Date();
4+
nextMonthExpiry.setMonth(nextMonthExpiry.getMonth() + 1);
35

46
const automationAccounts = [
57
{
@@ -31,7 +33,7 @@ const webhooks = [
3133
"id": "/subscriptions/12345/resourceGroups/test-rg/providers/Microsoft.Automation/automationAccounts/test-automationacct/webhooks/test1",
3234
"name": "test1",
3335
"creationTime": "2024-01-22T13:33:52.1066667+00:00",
34-
"expiryTime": "2025-01-22T13:33:52.1066667+00:00",
36+
"expiryTime": nextMonthExpiry,
3537
},
3638
{
3739
"id": "/subscriptions/12345/resourceGroups/test-rg/providers/Microsoft.Automation/automationAccounts/test-automationacct/webhooks/test2",

0 commit comments

Comments
 (0)