diff --git a/exports.js b/exports.js index 9e3d16bd64..7ddbaf1e9c 100644 --- a/exports.js +++ b/exports.js @@ -111,6 +111,9 @@ module.exports = { 'unassociatedElasticIp' : require(__dirname + '/plugins/aws/ec2/unassociatedElasticIp.js'), 'subnetIpAvailability' : require(__dirname + '/plugins/aws/ec2/subnetIpAvailability.js'), 'excessiveSecurityGroups' : require(__dirname + '/plugins/aws/ec2/excessiveSecurityGroups.js'), + + 'enhancedMetadataEnabled' : require(__dirname + '/plugins/aws/imagebuilder/enhancedMetadataEnabled.js'), + 'instanceLimit' : require(__dirname + '/plugins/aws/ec2/instanceLimit.js'), 'instanceVcpusLimit' : require(__dirname + '/plugins/aws/ec2/instanceVcpusLimit.js'), 'instanceMaxCount' : require(__dirname + '/plugins/aws/ec2/instanceMaxCount.js'), diff --git a/helpers/aws/api.js b/helpers/aws/api.js index 06da9d317d..2638e484a7 100644 --- a/helpers/aws/api.js +++ b/helpers/aws/api.js @@ -698,6 +698,12 @@ var calls = { override: true } }, + Imagebuilder: { + listImagePipelines: { + property: 'imagePipelineList', + paginate: 'nextToken' + } + }, IoTSiteWise: { describeDefaultEncryptionConfiguration: { } diff --git a/helpers/aws/regions.js b/helpers/aws/regions.js index 0a2feeefe3..a692d75b88 100644 --- a/helpers/aws/regions.js +++ b/helpers/aws/regions.js @@ -192,6 +192,7 @@ module.exports = { appmesh: ['us-east-1', 'us-east-2', 'us-west-1', 'us-west-2', 'ca-central-1', 'eu-central-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'eu-north-1', 'ap-northeast-1', 'ap-northeast-2', 'eu-south-1', 'ap-southeast-1', 'ap-southeast-2', 'ap-south-1', 'sa-east-1', 'ap-east-1', 'me-south-1', 'af-south-1'], + imagebuilder: [...regions, ...newRegions], frauddetector: ['us-east-1', 'us-east-2', 'us-west-2', 'eu-west-1', 'ap-southeast-1', 'ap-southeast-2'], computeoptimizer: ['us-east-1'], appconfig: [...regions, ...newRegions] diff --git a/helpers/aws/regions_china.js b/helpers/aws/regions_china.js index 7ffaef5484..072dc60f03 100644 --- a/helpers/aws/regions_china.js +++ b/helpers/aws/regions_china.js @@ -117,6 +117,7 @@ module.exports = { voiceid: regions, appmesh: regions, frauddetector: regions, - computeoptimizer: ['cn-north-1'], + imagebuilder: regions, + computeoptimizer: regions, appconfig: regions }; diff --git a/helpers/aws/regions_gov.js b/helpers/aws/regions_gov.js index e86ba16fe2..89f74e20ab 100644 --- a/helpers/aws/regions_gov.js +++ b/helpers/aws/regions_gov.js @@ -116,6 +116,7 @@ module.exports = { voiceid: regions, appmesh: regions, frauddetector: regions, - computeoptimizer: ['us-gov-west-1'], + imagebuilder: regions, + computeoptimizer: regions, appconfig: regions }; diff --git a/plugins/aws/imagebuilder/enhancedMetadataEnabled.js b/plugins/aws/imagebuilder/enhancedMetadataEnabled.js new file mode 100644 index 0000000000..3559af7703 --- /dev/null +++ b/plugins/aws/imagebuilder/enhancedMetadataEnabled.js @@ -0,0 +1,58 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'Enhanced Metadata Collection Enabled', + category: 'Image Builder', + domain: 'Compute', + severity: 'LOW', + description: 'Ensure that enhanced metadata collection is enabled for image pipelines.', + more_info: 'EC2 Image Builder is a fully managed AWS service that makes it easier to automate the creation, management, and deployment of customized, secure, and up-to-date server images that are pre-installed and pre-configured with software and settings to meet specific IT standards.', + link: 'https://docs.aws.amazon.com/imagebuilder/latest/userguide/start-build-image-pipeline.html', + recommended_action: 'Enable enhanced metadata collection for image pipeline.', + apis: ['Imagebuilder:listImagePipelines'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + async.each(regions.imagebuilder, function(region, rcb){ + var listImagePipelines = helpers.addSource(cache, source, + ['imagebuilder', 'listImagePipelines', region]); + + if (!listImagePipelines) return rcb(); + + if (listImagePipelines.err || !listImagePipelines.data) { + helpers.addResult(results, 3, + 'Unable to list image pipeline: ' + helpers.addError(listImagePipelines), region); + return rcb(); + } + + if (!listImagePipelines.data.length) { + helpers.addResult(results, 0, + 'No Image Builder image pipelines found', region); + return rcb(); + } + + for (let image of listImagePipelines.data) { + if (!image.arn) continue; + + let resource = image.arn; + + if (image.enhancedImageMetadataEnabled) { + helpers.addResult(results, 0, + 'Image pipeline has enhanced metadata collection enabled', + region, resource); + } else { + helpers.addResult(results, 2, + 'Image pipeline does not have enhanced metadata collection enabled', + region, resource); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/aws/imagebuilder/enhancedMetadataEnabled.spec.js b/plugins/aws/imagebuilder/enhancedMetadataEnabled.spec.js new file mode 100644 index 0000000000..794cb0d441 --- /dev/null +++ b/plugins/aws/imagebuilder/enhancedMetadataEnabled.spec.js @@ -0,0 +1,109 @@ +var expect = require('chai').expect;; +var enhancedMetadataEnabled = require('./enhancedMetadataEnabled'); + +const listImagePipelines = [ + { + "arn": "arn:aws:imagebuilder:us-east-1:000011112222:image-pipeline/akhtar-img-pipeline", + "name": "akhtar-img-pipeline", + "platform": "Linux", + "enhancedImageMetadataEnabled": true, + "imageRecipeArn": "arn:aws:imagebuilder:us-east-1:000011112222:image-recipe/akhtar-img-rc/1.0.0", + "infrastructureConfigurationArn": "arn:aws:imagebuilder:us-east-1:000011112222:infrastructure-configuration/akhtar-img-pipeline-914d5fdf-45db-4231-ae0e-991c39f9e594", + "distributionConfigurationArn": "arn:aws:imagebuilder:us-east-1:000011112222:distribution-configuration/akhtar-img-pipeline-914d5fdf-45db-4231-ae0e-991c39f9e594", + "imageTestsConfiguration": { + "imageTestsEnabled": true, + "timeoutMinutes": 720 + }, + "status": "ENABLED", + "dateCreated": "2022-03-08T11:20:43.395Z", + "dateUpdated": "2022-03-08T11:20:43.395Z", + "tags": {} + }, + { + "arn": "arn:aws:imagebuilder:us-east-1:000011112222:image-pipeline/akhtar-img-pipeline", + "name": "akhtar-img-pipeline", + "platform": "Linux", + "enhancedImageMetadataEnabled": false, + "imageRecipeArn": "arn:aws:imagebuilder:us-east-1:000011112222:image-recipe/akhtar-img-rc/1.0.0", + "infrastructureConfigurationArn": "arn:aws:imagebuilder:us-east-1:000011112222:infrastructure-configuration/akhtar-img-pipeline-914d5fdf-45db-4231-ae0e-991c39f9e594", + "distributionConfigurationArn": "arn:aws:imagebuilder:us-east-1:000011112222:distribution-configuration/akhtar-img-pipeline-914d5fdf-45db-4231-ae0e-991c39f9e594", + "imageTestsConfiguration": { + "imageTestsEnabled": true, + "timeoutMinutes": 720 + }, + "status": "ENABLED", + "dateCreated": "2022-03-08T11:20:43.395Z", + "dateUpdated": "2022-03-08T11:20:43.395Z", + "tags": {} + } +]; + +const createCache = (images) => { + return { + imagebuilder: { + listImagePipelines: { + "us-east-1": { + data: images + } + } + } + } +} + +const createNullCache = () => { + return { + imagebuilder: { + listImagePipelines: { + "us-east-1": { + data: null + } + } + } + } +} + +describe('enhancedMetadataEnabled', () => { + describe('run', () => { + it('should PASS if Image pipeline has enhanced metadata collection enabled', () => { + const cache = createCache([listImagePipelines[0]]); + enhancedMetadataEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Image pipeline has enhanced metadata collection enabled'); + expect(results[0].region).to.equal('us-east-1'); + }) + }); + it('should FAIL if Image pipeline does not have enhanced metadata collection enabled', () => { + const cache = createCache([listImagePipelines[1]]); + enhancedMetadataEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Image pipeline does not have enhanced metadata collection enabled'); + expect(results[0].region).to.equal('us-east-1'); + }) + }); + it('should PASS if No image pipeline list found', () => { + const cache = createCache([]); + enhancedMetadataEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('No Image Builder image pipelines found'); + expect(results[0].region).to.equal('us-east-1'); + }) + }); + it('should UNKNOWN if Unable to list image pipeline', () => { + const cache = createNullCache(); + enhancedMetadataEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].message).to.include('Unable to list image pipeline'); + expect(results[0].region).to.equal('us-east-1'); + }) + }); + it('should not return anything if list image pipeline response is not found', () => { + enhancedMetadataEnabled.run({}, {}, (err, results) => { + expect(results.length).to.equal(0); + }) + }); + }); +});