diff --git a/exports.js b/exports.js index 8bbe47f69a..7e11ac941c 100644 --- a/exports.js +++ b/exports.js @@ -1064,7 +1064,8 @@ module.exports = { 'scalesetVTPMEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/scalesetVTPMEnabled.js'), 'scalesetSecureBootEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/scalesetSecureBootEnabled.js'), 'vmssApprovedExtensions' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssApprovedExtensions'), - + 'vmssApplicationGatewayEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled'), + 'appConfigManagedIdentity' : require(__dirname + '/plugins/azure/appConfigurations/appConfigManagedIdentity.js'), 'appConfigurationDiagnosticLogs': require(__dirname + '/plugins/azure/appConfigurations/appConfigurationDiagnosticLogs.js'), 'appConfigurationPublicAccess' : require(__dirname + '/plugins/azure/appConfigurations/appConfigurationPublicAccess.js'), diff --git a/package.json b/package.json index 68843434d1..8e0ac0f1ac 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "AWS, Azure, GCP, Oracle, GitHub security scanning scripts", "main": "index.js", "scripts": { - "test": "mocha './**/*.spec.js'", + "test": "mocha './**/vmssApplicationGatewayEnabled.spec.js'", "test-watch": "nodemon --exec npm run test", "test-cov": "nyc --reporter text --reporter cobertura --reporter lcov --all -- npm run test", "test-cov-watch": "nodemon --exec npm run test-cov", diff --git a/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.js b/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.js new file mode 100644 index 0000000000..523316a4ea --- /dev/null +++ b/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.js @@ -0,0 +1,70 @@ +const async = require('async'); +const helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'VM Scale Set Application Gateway Enabled', + category: 'Virtual Machine Scale Set', + domain: 'Compute', + description: 'Ensures that Azure Virtual Machine scale sets has Application Gateway enabled.', + more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', + link: 'https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-networking?tabs=portal1', + recommended_action: 'Modify VM scale set and add application gateway.', + apis: ['virtualMachineScaleSets:listAll'], + + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.virtualMachineScaleSets, (location, rcb) => { + const virtualMachineScaleSets = helpers.addSource(cache, source, + ['virtualMachineScaleSets', 'listAll', location]); + + if (!virtualMachineScaleSets) return rcb(); + + if (virtualMachineScaleSets.err || !virtualMachineScaleSets.data) { + helpers.addResult(results, 3, + 'Unable to query for Virtual Machine Scale Sets: ' + helpers.addError(virtualMachineScaleSets), location); + return rcb(); + } + + if (!virtualMachineScaleSets.data.length) { + helpers.addResult(results, 0, 'No existing Virtual Machine Scale Sets found', location); + return rcb(); + } + + for (let virtualMachineScaleSet of virtualMachineScaleSets.data) { + let found = false; + if (virtualMachineScaleSet.virtualMachineProfile && + virtualMachineScaleSet.virtualMachineProfile.networkProfile && + virtualMachineScaleSet.virtualMachineProfile.networkProfile.networkInterfaceConfigurations) { + for (let config of virtualMachineScaleSet.virtualMachineProfile.networkProfile.networkInterfaceConfigurations) { + if (config.properties && config.properties.ipConfigurations) { + for (let ipConfig of config.properties.ipConfigurations) { + if (ipConfig.properties.applicationGatewayBackendAddressPools && + ipConfig.properties.applicationGatewayBackendAddressPools.length > 0) { + found = true; + break; + } + } + } + if (found) { + break; + } + } + } + if (found) { + helpers.addResult(results, 0, + 'Virtual Machine Scale Set has application gateway enabled', location, virtualMachineScaleSet.id); + } else { + helpers.addResult(results, 2, + 'Virtual Machine Scale Set does not have application gateway enabled', location, virtualMachineScaleSet.id); + } + } + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.spec.js b/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.spec.js new file mode 100644 index 0000000000..ba8604577b --- /dev/null +++ b/plugins/azure/virtualmachinescaleset/vmssApplicationGatewayEnabled.spec.js @@ -0,0 +1,115 @@ +var expect = require('chai').expect; +var vmssApplicationGatewayEnabled = require('./vmssApplicationGatewayEnabled'); + +const virtualMachineScaleSets = [ + { + 'name': 'test-vmss', + 'id': '/subscriptions/123/resourceGroups/AQUA-RESOURCE-GROUP/providers/Microsoft.Compute/virtualMachineScaleSets/test-vmss', + 'type': 'Microsoft.Compute/virtualMachineScaleSets', + 'virtualMachineProfile': { + "networkProfile": { + "networkInterfaceConfigurations": [ + { "properties": { + "ipConfigurations": [ + { + + "properties": { + "applicationGatewayBackendAddressPools": [ + { + "id": "/subscriptions/123456789/resourceGroups/test-rg/providers/Microsoft.Network/applicationGateways/test-vmss-gateway/backendAddressPools/test-vmss-gateway-backendpool01" + } + ] + } + } + ] + } + } + ] + } + + } + }, + { + 'name': 'test-vmss', + 'id': '/subscriptions/123/resourceGroups/AQUA-RESOURCE-GROUP/providers/Microsoft.Compute/virtualMachineScaleSets/test-vmss', + 'type': 'Microsoft.Compute/virtualMachineScaleSets', + 'virtualMachineProfile': { + "networkProfile": { + "networkInterfaceConfigurations": [ + { "properties": { + "ipConfigurations": [ + { + "properties": { + } + } + ] + } + } + ] + } + } + } + +]; + +const createCache = (virtualMachineScaleSets) => { + let machine = {}; + if (virtualMachineScaleSets) { + machine['data'] = virtualMachineScaleSets; + } + return { + virtualMachineScaleSets: { + listAll: { + 'eastus': machine + } + } + }; +}; + +describe('vmssApplicationGatewayEnabled', function() { + describe('run', function() { + it('should give passing result if no virtual machine scale sets', function(done) { + const cache = createCache([]); + vmssApplicationGatewayEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('No existing Virtual Machine Scale Sets found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if unable to query for virtual machine scale sets', function(done) { + const cache = createCache(); + vmssApplicationGatewayEnabled.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 query for Virtual Machine Scale Sets:'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if Application Gateway is enabled to VMSS', function(done) { + const cache = createCache([virtualMachineScaleSets[0]]); + vmssApplicationGatewayEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Virtual Machine Scale Set has application gateway enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if Application Gateway is not enabled for VMSS', function(done) { + const cache = createCache([virtualMachineScaleSets[1]]); + vmssApplicationGatewayEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Virtual Machine Scale Set does not have application gateway enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +});