Skip to content

Commit 0679196

Browse files
authored
Merge pull request #2023 from aquasecurity/bundles_sync/29_05
syncing with saas
2 parents 74a3d05 + 033b005 commit 0679196

24 files changed

+395
-141
lines changed

collectors/aws/ec2/describeSnapshots.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ var helpers = require(__dirname + '/../../../helpers/aws');
88
module.exports = function(AWSConfig, collection, retries, callback) {
99
var ec2 = new AWS.EC2(AWSConfig);
1010
var sts = new AWS.STS(AWSConfig);
11+
var paginating = false;
1112

1213
helpers.makeCustomCollectorCall(sts, 'getCallerIdentity', {}, retries, null, null, null, function(stsErr, stsData) {
1314
if (stsErr || !stsData.Account) {
@@ -16,6 +17,7 @@ module.exports = function(AWSConfig, collection, retries, callback) {
1617
}
1718

1819
var params = {
20+
MaxResults: 1000,
1921
Filters: [
2022
{
2123
Name: 'owner-id',
@@ -32,13 +34,36 @@ module.exports = function(AWSConfig, collection, retries, callback) {
3234
]
3335
};
3436

35-
helpers.makeCustomCollectorCall(ec2, 'describeSnapshots', params, retries, null, null, null, function(err, data) {
37+
var paginateCb = function(err, data) {
3638
if (err) {
3739
collection.ec2.describeSnapshots[AWSConfig.region].err = err;
38-
} else {
39-
collection.ec2.describeSnapshots[AWSConfig.region].data = data.Snapshots;
40+
} else if (data) {
41+
if (paginating && data.Snapshots && data.Snapshots.length &&
42+
collection.ec2.describeSnapshots[AWSConfig.region].data &&
43+
collection.ec2.describeSnapshots[AWSConfig.region].data.length) {
44+
collection.ec2.describeSnapshots[AWSConfig.region].data = collection.ec2.describeSnapshots[AWSConfig.region].data.concat(data.Snapshots);
45+
} else if (!paginating) {
46+
collection.ec2.describeSnapshots[AWSConfig.region].data = data.Snapshots;
47+
}
48+
if (data.NextToken &&
49+
collection.ec2.describeSnapshots[AWSConfig.region].data &&
50+
collection.ec2.describeSnapshots[AWSConfig.region].data.length) {
51+
paginating = true;
52+
return execute(data.NextToken);
53+
}
4054
}
55+
4156
callback();
42-
});
57+
};
58+
function execute(nextToken) { // eslint-disable-line no-inner-declarations
59+
var localParams = JSON.parse(JSON.stringify(params || {}));
60+
if (nextToken) localParams['NextToken'] = nextToken;
61+
if (nextToken) {
62+
helpers.makeCustomCollectorCall(ec2, 'describeSnapshots', localParams, retries, null, null, null, paginateCb);
63+
} else {
64+
helpers.makeCustomCollectorCall(ec2, 'describeSnapshots', params, retries, null, null, null, paginateCb);
65+
}
66+
}
67+
execute();
4368
});
44-
};
69+
};

exports.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ module.exports = {
5353
'workgroupEnforceConfiguration' : require(__dirname + '/plugins/aws/athena/workgroupEnforceConfiguration.js'),
5454

5555
'customModelInVpc' :require(__dirname + '/plugins/aws/bedrock/customModelInVpc.js'),
56+
'bedrockInUse' :require(__dirname + '/plugins/aws/bedrock/bedrockInUse.js'),
5657
'privateCustomModel' :require(__dirname + '/plugins/aws/bedrock/privateCustomModel.js'),
5758
'customModelHasTags' :require(__dirname + '/plugins/aws/bedrock/customModelHasTags.js'),
5859
'modelInvocationLoggingEnabled' :require(__dirname + '/plugins/aws/bedrock/modelInvocationLoggingEnabled.js'),
@@ -725,7 +726,7 @@ module.exports = {
725726

726727
'workspacePublicAccessDisabled' : require(__dirname + '/plugins/azure/machinelearning/workspacePublicAccessDisabled.js'),
727728
'workspaceLoggingEnabled' : require(__dirname + '/plugins/azure/machinelearning/workspaceLoggingEnabled.js'),
728-
'mlWorkspaceHasTags' : require(__dirname + '/plugins/azure/machinelearning/mlWorkspaceHasTags.js'),
729+
'mlWorkspaceHasTags' : require(__dirname + '/plugins/azure/machinelearning/mlWorkspaceHasTags.js'),
729730

730731

731732
'minimumTlsVersion' : require(__dirname + '/plugins/azure/redisCache/minimumTlsVersion.js'),

helpers/aws/api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,10 @@ var calls = {
14491449
describeDBClusters: {
14501450
property: 'DBClusters',
14511451
paginate: 'Marker'
1452+
},
1453+
describeDBInstances: {
1454+
property: 'DBInstances',
1455+
paginate: 'Marker'
14521456
}
14531457
},
14541458
Organizations: {

helpers/aws/api_multipart.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,10 @@ var calls = [
838838
describeDBClusters: {
839839
property: 'DBClusters',
840840
paginate: 'Marker'
841+
},
842+
describeDBInstances: {
843+
property: 'DBInstances',
844+
paginate: 'Marker'
841845
}
842846
},
843847
Organizations: {

plugins/aws/bedrock/bedrockInUse.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
var async = require('async');
2+
var helpers = require('../../../helpers/aws');
3+
4+
module.exports = {
5+
title: 'AWS Bedrock In Use',
6+
category: 'AI & ML',
7+
domain: 'Machine Learning',
8+
severity: 'Low',
9+
description: 'Ensures that AWS Bedrock service is in use within your AWS account.',
10+
more_info: 'AWS Bedrock provides access to high-performing foundation models from leading AI startups and Amazon through a unified API, enabling easy experimentation, customization, and deployment of generative AI applications with robust security and privacy features.',
11+
link: 'https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html',
12+
recommended_action: 'Use Bedrock service to utilize top foundation models with strong security and customization.',
13+
apis: ['Bedrock:listCustomModels'],
14+
realtime_triggers: ['bedrock:DeleteCustomModel'],
15+
16+
run: function(cache, settings, callback) {
17+
var results = [];
18+
var source = {};
19+
var regions = helpers.regions(settings);
20+
21+
async.each(regions.bedrock, function(region, rcb){
22+
var listCustomModels = helpers.addSource(cache, source,
23+
['bedrock', 'listCustomModels', region]);
24+
25+
if (!listCustomModels) return rcb();
26+
27+
if (listCustomModels.err && listCustomModels.err.message.includes('Unknown operation')) {
28+
helpers.addResult(results, 0,
29+
'Custom model service is not available in this region', region);
30+
return rcb();
31+
}
32+
33+
if (listCustomModels.err || !listCustomModels.data) {
34+
helpers.addResult(results, 3,
35+
`Unable to query for Bedrock custom model list: ${helpers.addError(listCustomModels)}`, region);
36+
return rcb();
37+
}
38+
39+
if (!listCustomModels.data.length) {
40+
helpers.addResult(results, 2, 'Bedrock service is not in use', region);
41+
return rcb();
42+
} else {
43+
helpers.addResult(results, 0, 'Bedrock service is in use', region);
44+
return rcb();
45+
46+
}
47+
48+
}, function(){
49+
callback(null, results, source);
50+
});
51+
}
52+
};
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
var expect = require('chai').expect;
2+
const bedrockInUse = require('./bedrockInUse');
3+
4+
const listCustomModels = [
5+
{
6+
"modelArn": "arn:aws:bedrock:us-east-1:11223344:custom-model/amazon.titan-text-lite-v1:0:4k/2ytyyx8nid0h",
7+
"modelName": "model2",
8+
"creationTime": "2023-11-29T10:45:43.056000+00:00",
9+
"baseModelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-text-lite-v1:0:4k",
10+
"baseModelName": ""
11+
},
12+
{
13+
"modelArn": "arn:aws:bedrock:us-east-1:11223344:custom-model/amazon.titan-text-lite-v1:0:4k/vjqsydtdhkpz",
14+
"modelName": "testmodel2",
15+
"creationTime": "2023-11-28T11:29:18.655000+00:00",
16+
"baseModelArn": "arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-text-lite-v1:0:4k",
17+
"baseModelName": ""
18+
}
19+
];
20+
21+
22+
const createCache = (listModels) => {
23+
return {
24+
bedrock: {
25+
listCustomModels: {
26+
'us-east-1': {
27+
err: null,
28+
data: listModels
29+
}
30+
},
31+
}
32+
};
33+
};
34+
35+
36+
describe('bedrockInUse', function () {
37+
describe('run', function () {
38+
it('should PASS if Bedrock service is in use', function (done) {
39+
const cache = createCache([listCustomModels[0]]);
40+
bedrockInUse.run(cache, {}, (err, results) => {
41+
expect(results.length).to.equal(1);
42+
expect(results[0].status).to.equal(0);
43+
expect(results[0].region).to.equal('us-east-1');
44+
expect(results[0].message).to.include('Bedrock service is in use')
45+
done();
46+
});
47+
});
48+
49+
it('should FAIL if Bedrock service is not in use', function (done) {
50+
const cache = createCache([]);
51+
bedrockInUse.run(cache, {}, (err, results) => {
52+
expect(results.length).to.equal(1);
53+
expect(results[0].status).to.equal(2);
54+
expect(results[0].region).to.equal('us-east-1');
55+
expect(results[0].message).to.include('Bedrock service is not in use')
56+
done();
57+
});
58+
});
59+
60+
61+
it('should UNKNOWN if unable to query Bedrock custom model', function (done) {
62+
const cache = createCache(null, null);
63+
bedrockInUse.run(cache, {}, (err, results) => {
64+
expect(results.length).to.equal(1);
65+
expect(results[0].status).to.equal(3);
66+
expect(results[0].region).to.equal('us-east-1');
67+
expect(results[0].message).to.include('Unable to query for Bedrock custom model list')
68+
done();
69+
});
70+
});
71+
72+
});
73+
});

plugins/aws/ec2/appTierInstanceIamRole.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
more_info: 'EC2 instances should have IAM roles configured with necessary permission to access other AWS services',
1212
link: 'https://aws.amazon.com/blogs/security/new-attach-an-aws-iam-role-to-an-existing-amazon-ec2-instance-by-using-the-aws-cli/',
1313
recommended_action: 'Modify EC2 instances to attach IAM roles with required IAM policies',
14-
apis: ['EC2:describeInstances', 'EC2:describeTags', 'IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies'],
14+
apis: ['EC2:describeInstances', 'IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies'],
1515
settings: {
1616
ec2_app_tier_tag_key: {
1717
name: 'EC2 App-Tier Tag Key',
@@ -71,14 +71,8 @@ module.exports = {
7171
var resource = `arn:${awsOrGov}:ec2:${region}:${accountId}:instance/${entry.InstanceId}`;
7272

7373
var tagFound = false;
74-
for (let t in describeTags.data) {
75-
let tag = describeTags.data[t];
76-
77-
if (tag.ResourceId && tag.ResourceId === entry.InstanceId &&
78-
tag.Key && tag.Key === config.ec2_app_tier_tag_key) {
79-
tagFound = true;
80-
break;
81-
}
74+
if (entry.Tags && entry.Tags.length) {
75+
tagFound = entry.Tags.find(tag => tag.Key === config.ec2_app_tier_tag_key);
8276
}
8377

8478
if (!tagFound) {
@@ -93,7 +87,7 @@ module.exports = {
9387
} else {
9488
var roleNameArr = entry.IamInstanceProfile.Arn.split('/');
9589
var roleName = roleNameArr[roleNameArr.length-1];
96-
90+
9791
// Get managed policies attached to role
9892
var listAttachedRolePolicies = helpers.addSource(cache, source,
9993
['iam', 'listAttachedRolePolicies', region, roleName]);
@@ -136,10 +130,10 @@ module.exports = {
136130
}
137131
}
138132
}
139-
133+
140134
cb();
141135
});
142-
136+
143137
return rcb();
144138
}, function(){
145139
callback(null, results, source);

plugins/aws/ec2/webTierInstanceIamRole.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = {
1111
more_info: 'EC2 instances should have IAM roles configured with necessary permission to access other AWS services',
1212
link: 'https://aws.amazon.com/blogs/security/new-attach-an-aws-iam-role-to-an-existing-amazon-ec2-instance-by-using-the-aws-cli/',
1313
recommended_action: 'Modify EC2 instances to attach IAM roles with required IAM policies',
14-
apis: ['EC2:describeInstances', 'EC2:describeTags', 'IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies'],
14+
apis: ['EC2:describeInstances', 'IAM:listRoles', 'IAM:listRolePolicies', 'IAM:listAttachedRolePolicies'],
1515
settings: {
1616
ec2_web_tier_tag_key: {
1717
name: 'EC2 Web-Tier Tag Key',
@@ -71,14 +71,8 @@ module.exports = {
7171
var resource = `arn:${awsOrGov}:ec2:${region}:${accountId}:instance/${entry.InstanceId}`;
7272

7373
var tagFound = false;
74-
for (let t in describeTags.data) {
75-
let tag = describeTags.data[t];
76-
77-
if (tag.ResourceId && tag.ResourceId === entry.InstanceId &&
78-
tag.Key && tag.Key === config.ec2_web_tier_tag_key) {
79-
tagFound = true;
80-
break;
81-
}
74+
if (entry.Tags && entry.Tags.length) {
75+
tagFound = entry.Tags.find(tag => tag.Key === config.ec2_web_tier_tag_key);
8276
}
8377

8478
if (!tagFound) {
@@ -93,7 +87,7 @@ module.exports = {
9387
} else {
9488
var roleNameArr = entry.IamInstanceProfile.Arn.split('/');
9589
var roleName = roleNameArr[roleNameArr.length-1];
96-
90+
9791
// Get managed policies attached to role
9892
var listAttachedRolePolicies = helpers.addSource(cache, source,
9993
['iam', 'listAttachedRolePolicies', region, roleName]);
@@ -136,10 +130,10 @@ module.exports = {
136130
}
137131
}
138132
}
139-
133+
140134
cb();
141135
});
142-
136+
143137
return rcb();
144138
}, function(){
145139
callback(null, results, source);

plugins/aws/elbv2/elbv2TLSVersionCipherEnabled.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ module.exports = {
55
title: 'ELBv2 TLS Version and Cipher Header Disabled',
66
category: 'ELBv2',
77
domain: 'Content Delivery',
8-
severity: 'Medium',
8+
severity: 'low',
99
description: 'Ensures that AWS ELBv2 load balancers does not have TLS version and cipher headers enabled.',
10-
more_info: 'Disabling TLS version and cipher headers mitigates potential information leakage risks and aligns with security best practices, ensuring that sensitive details are not exposed to unauthorized parties.',
10+
more_info: 'TLS Version and Cipher Header provides information about the specific TLS version and cipher suite used during the establishment of the secure connection. Enabling the header might leak the sensitive information about the encryption protocols and algorithms being used',
1111
link: 'https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html',
1212
recommended_action: 'Update ELBv2 load balancer traffic configuration to disable TLS version and cipher headers',
1313
apis: ['ELBv2:describeLoadBalancers', 'ELBv2:describeLoadBalancerAttributes'],

plugins/aws/kms/kmsKeyRotation.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ module.exports = {
111111
return;
112112
}
113113

114+
if (describeKeyData.KeyMetadata && describeKeyData.KeyMetadata.KeySpec && describeKeyData.KeyMetadata.KeySpec !== 'SYMMETRIC_DEFAULT') {
115+
noCmks = false;
116+
helpers.addResult(results, 0, `Key rotation is not available for ${describeKeyData.KeyMetadata.KeySpec} key type`, region, kmsKey.KeyArn);
117+
return;
118+
}
119+
114120
var getKeyRotationStatus = helpers.addSource(cache, source,
115121
['kms', 'getKeyRotationStatus', region, kmsKey.KeyId]);
116122

plugins/aws/kms/kmsKeyRotation.spec.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const describeKey = [
2323
KeyState: "Enabled",
2424
KeyUsage: "ENCRYPT_DECRYPT",
2525
MultiRegion: false,
26-
Origin: "AWS_KMS"
26+
Origin: "AWS_KMS",
27+
KeySpec: "HMAC_512",
2728
}
2829
},
2930
{
@@ -42,7 +43,8 @@ const describeKey = [
4243
KeyState: "Enabled",
4344
KeyUsage: "ENCRYPT_DECRYPT",
4445
MultiRegion: false,
45-
Origin: "AWS_KMS"
46+
Origin: "AWS_KMS",
47+
KeySpec: "SYMMETRIC_DEFAULT",
4648
}
4749
},
4850
{
@@ -61,7 +63,8 @@ const describeKey = [
6163
KeyState: "PendingDeletion",
6264
KeyUsage: "ENCRYPT_DECRYPT",
6365
MultiRegion: false,
64-
Origin: "AWS_KMS"
66+
Origin: "AWS_KMS",
67+
KeySpec: "SYMMETRIC_DEFAULT",
6568
}
6669
}
6770
]
@@ -250,5 +253,16 @@ describe('kmsKeyRotation', function () {
250253
done();
251254
});
252255
});
256+
257+
it('should not pass if key rotation is not avaible for KMS ', function (done) {
258+
const cache = createCache([listKeys], describeKey[0], keyPolicy[0], keyRotationStatus[0]);
259+
kmsKeyRotation.run(cache, {}, (err, results) => {
260+
expect(results.length).to.equal(1);
261+
expect(results[0].status).to.equal(0);
262+
expect(results[0].region).to.equal('us-east-1');
263+
expect(results[0].message).to.include('Key rotation is not available for HMAC_512 key type');
264+
done();
265+
});
266+
});
253267
});
254268
});

0 commit comments

Comments
 (0)