diff --git a/exports.js b/exports.js index 912d562838..0c8b893a09 100644 --- a/exports.js +++ b/exports.js @@ -29,6 +29,7 @@ module.exports = { 'dynamoKmsEncryption' : require(__dirname + '/plugins/aws/dynamodb/dynamoKmsEncryption.js'), 'defaultSecurityGroup' : require(__dirname + '/plugins/aws/ec2/defaultSecurityGroup.js'), + 'launchWizardSecurityGroups' : require(__dirname + '/plugins/aws/ec2/launchWizardSecurityGroups'), 'elasticIpLimit' : require(__dirname + '/plugins/aws/ec2/elasticIpLimit.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), @@ -71,8 +72,9 @@ module.exports = { 'ebsSnapshotPrivate' : require(__dirname + '/plugins/aws/ec2/ebsSnapshotPrivate.js'), 'natMultiAz' : require(__dirname + '/plugins/aws/ec2/natMultiAz.js'), 'defaultVpcInUse' : require(__dirname + '/plugins/aws/ec2/defaultVpcInUse.js'), - 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), + 'defaultVpcExists' : require(__dirname + '/plugins/aws/ec2/defaultVpcExists.js'), 'crossVpcPublicPrivate' : require(__dirname + '/plugins/aws/ec2/crossVpcPublicPrivate.js'), + 'vpcEndpointAcceptance' : require(__dirname + '/plugins/aws/ec2/vpcEndpointAcceptance'), 'ebsEncryptedSnapshots' : require(__dirname + '/plugins/aws/ec2/ebsEncryptedSnapshots.js'), 'ec2MetadataOptions' : require(__dirname + '/plugins/aws/ec2/ec2MetadataOptions.js'), diff --git a/plugins/aws/ec2/ec2MetadataOptions.js b/plugins/aws/ec2/ec2MetadataOptions.js index d0a065fdc5..6dae5110e4 100644 --- a/plugins/aws/ec2/ec2MetadataOptions.js +++ b/plugins/aws/ec2/ec2MetadataOptions.js @@ -6,7 +6,7 @@ module.exports = { title: 'Insecure EC2 Metadata Options', category: 'EC2', description: 'Ensures EC2 instance metadata is updated to require HttpTokens or disable HttpEndpoint', - more_info: 'The new EC2 metadata service prevents SSRF attack escalations from accessing the senstive instance metadata endpoints.', + more_info: 'The new EC2 metadata service prevents SSRF attack escalations from accessing the sensitive instance metadata endpoints.', link: 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#configuring-instance-metadata-service', recommended_action: 'Update instance metadata options to use IMDSv2', apis: ['EC2:describeInstances'], diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.js b/plugins/aws/ec2/launchWizardSecurityGroups.js new file mode 100644 index 0000000000..252cabd11c --- /dev/null +++ b/plugins/aws/ec2/launchWizardSecurityGroups.js @@ -0,0 +1,55 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'EC2 LaunchWizard Security Groups', + category: 'EC2', + description: 'Ensures security groups created by the EC2 launch wizard are not used', + more_info: 'The EC2 launch wizard frequently creates insecure security groups that are exposed publicly. These groups should not be used and custom security groups should be created instead.', + link: 'https://docs.aws.amazon.com/launchwizard/latest/userguide/launch-wizard-sap-security-groups.html', + recommended_action: 'Delete the launch wizard security group and replace it with a custom security group.', + apis: ['EC2:describeSecurityGroups'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + async.each(regions.ec2, function(region, rcb){ + var describeSecurityGroups = helpers.addSource(cache, source, + ['ec2', 'describeSecurityGroups', region]); + + if (!describeSecurityGroups) return rcb(); + + if (describeSecurityGroups.err || !describeSecurityGroups.data) { + helpers.addResult(results, 3, + 'Unable to query for security groups: ' + helpers.addError(describeSecurityGroups), region); + return rcb(); + } + + if (!describeSecurityGroups.data.length) { + helpers.addResult(results, 0, 'No security groups present', region); + return rcb(); + } + + for (var s in describeSecurityGroups.data) { + var sg = describeSecurityGroups.data[s]; + var resource = sg.GroupId; + + if (sg.GroupName.toLowerCase().startsWith('launch-wizard')) { + helpers.addResult(results, 2, + 'Security Group ' + sg.GroupName + ' was launched using EC2 launch wizard', + region, resource); + } else { + helpers.addResult(results, 0, + 'Security Group ' + sg.GroupName + ' was not launched using EC2 launch wizard', + region, resource); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/aws/ec2/launchWizardSecurityGroups.spec.js b/plugins/aws/ec2/launchWizardSecurityGroups.spec.js new file mode 100644 index 0000000000..a2b8baa2e9 --- /dev/null +++ b/plugins/aws/ec2/launchWizardSecurityGroups.spec.js @@ -0,0 +1,153 @@ +var expect = require('chai').expect; +const launchWizardSecurityGroups = require('./launchWizardSecurityGroups'); + +const securityGroups = [ + { + "Description": "launch-wizard-1 created 2020-08-10T14:28:09.271+05:00", + "GroupName": "launch-wizard-1", + "IpPermissions": [ + { + "FromPort": 22, + "IpProtocol": "tcp", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [], + "PrefixListIds": [], + "ToPort": 22, + "UserIdGroupPairs": [] + } + ], + "OwnerId": "560213429563", + "GroupId": "sg-0ff1642cae23c309a", + "IpPermissionsEgress": [ + { + "IpProtocol": "-1", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [], + "PrefixListIds": [], + "UserIdGroupPairs": [] + } + ], + "Tags": [], + "VpcId": "vpc-99de2fe4" + }, + { + "Description": "Allows SSh access to developer", + "GroupName": "spec-test-sg", + "IpPermissions": [], + "OwnerId": "560213429563", + "GroupId": "sg-0b5f2771716acfee4", + "IpPermissionsEgress": [ + { + "FromPort": 22, + "IpProtocol": "tcp", + "IpRanges": [ + { + "CidrIp": "0.0.0.0/0" + } + ], + "Ipv6Ranges": [ + { + "CidrIpv6": "::/0" + } + ], + "PrefixListIds": [], + "ToPort": 22, + "UserIdGroupPairs": [] + } + ], + "Tags": [], + "VpcId": "vpc-99de2fe4" + } + ]; + +const createCache = (securityGroups) => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': { + data: securityGroups + }, + }, + }, + }; +}; + +const createErrorCache = () => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': { + err: { + message: 'error describing security groups' + }, + }, + }, + }, + }; +}; + +const createNullCache = () => { + return { + ec2: { + describeSecurityGroups: { + 'us-east-1': null, + }, + }, + }; +}; + +describe('launchWizardSecurityGroups', function () { + describe('run', function () { + it('should PASS if security groups was not created using EC2 launch wizard', function (done) { + const cache = createCache([securityGroups[1]]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should FAIL if security groups was created using EC2 launch wizard', function (done) { + const cache = createCache([securityGroups[0]]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + done(); + }); + }); + + it('should PASS if no security groups are detected', function (done) { + const cache = createCache([]); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + done(); + }); + }); + + it('should UNKNOWN if there was an error describing security groups', function (done) { + const cache = createErrorCache(); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + done(); + }); + }); + + it('should not return any results if unable to query for security groups', function (done) { + const cache = createNullCache(); + launchWizardSecurityGroups.run(cache, {}, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + }); +}); diff --git a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js index 0946f5a682..62053b7238 100644 --- a/plugins/aws/ec2/vpcEndpointAcceptance.spec.js +++ b/plugins/aws/ec2/vpcEndpointAcceptance.spec.js @@ -112,15 +112,6 @@ describe('vpcEndpointAcceptance', function () { }); }); - it('should PASS if no VPC endpoint services are detected', function (done) { - const cache = createCache([]); - vpcEndpointAcceptance.run(cache, {}, (err, results) => { - expect(results.length).to.equal(1); - expect(results[0].status).to.equal(0); - done(); - }); - }); - it('should UNKNOWN if there was an error querying for VPC endpoint services', function (done) { const cache = createErrorCache(); vpcEndpointAcceptance.run(cache, {}, (err, results) => { diff --git a/plugins/google/vpcnetwork/defaultVpcInUse.js b/plugins/google/vpcnetwork/defaultVpcInUse.js index b0e773e322..9b2976037b 100644 --- a/plugins/google/vpcnetwork/defaultVpcInUse.js +++ b/plugins/google/vpcnetwork/defaultVpcInUse.js @@ -42,7 +42,7 @@ module.exports = { if (network.name == 'default') { defVPC = true; vpcUrl = network.selfLink; - } + } }); if (!defVPC) { helpers.addResult(results, 0, 'No default VPC found', 'global'); @@ -52,9 +52,9 @@ module.exports = { async.each(regions.zones, function(location, icb){ location.forEach(loc => { - let instances = helpers.addSource( - cache, source, ['instances', 'list', loc]); - + let instances = helpers.addSource(cache, source, + ['instances', 'compute','list', loc]); + if (!instances || instances.err || !instances.data) { } else if (instances.data.length) { instances.data.forEach(instance => { @@ -83,4 +83,4 @@ module.exports = { callback(null, results, source); }); } -} \ No newline at end of file +}