diff --git a/exports.js b/exports.js index 67caea23bc..116597ad25 100644 --- a/exports.js +++ b/exports.js @@ -1106,6 +1106,7 @@ module.exports = { 'vmssManagedIdentityEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssManagedIdentityEnabled.js'), 'scalesetVTPMEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/scalesetVTPMEnabled.js'), 'scalesetSecureBootEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/scalesetSecureBootEnabled.js'), + 'vmssWindowsAntiMalwareExt' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.js'), 'vmssApprovedExtensions' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssApprovedExtensions'), 'vmssBootDiagnosticsEnabled' : require(__dirname + '/plugins/azure/virtualmachinescaleset/vmssBootDiagnosticsEnabled'), diff --git a/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.js b/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.js new file mode 100644 index 0000000000..baf469d442 --- /dev/null +++ b/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.js @@ -0,0 +1,67 @@ +var async = require('async'); + +var helpers = require('../../../helpers/azure/'); + +module.exports = { + title: 'VMSS Windows AntiMalware Extension', + category: 'Virtual Machine Scale Set', + domain: 'Compute', + description: 'Ensures that Virtual Machine Scale Set windows instances have IaaS AntiMalware extension installed', + more_info: 'The VM Scale Set Windows AntiMalware Extension provides real-time protection against viruses, spyware, and other malicious software for virtual machine scale sets running on the Windows operating system.', + recommended_action: 'Modify Virtual Machine Scale Set and install IaaS AntiMalware extension.', + link: 'https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/iaas-antimalware-windows', + apis: ['virtualMachineScaleSets:listAll'], + realtime_triggers: ['microsoftcompute:virtualmachinescalesets:write', 'microsoftcompute:virtualmachinescalesets:delete', 'microsoftcompute:virtualmachinescalesets:extensions:write', 'microsoftcompute:virtualmachinescalesets:extensions:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.virtualMachineScaleSets, function(location, rcb) { + var 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 scaleSet of virtualMachineScaleSets.data) { + if (!scaleSet.id || + (scaleSet.virtualMachineProfile && + scaleSet.virtualMachineProfile.storageProfile && + scaleSet.virtualMachineProfile.storageProfile.osDisk && + scaleSet.virtualMachineProfile.storageProfile.osDisk.osType && + scaleSet.virtualMachineProfile.storageProfile.osDisk.osType.toLowerCase() != 'windows')) continue; + + const scaleSetExtensions = scaleSet.virtualMachineProfile && + scaleSet.virtualMachineProfile.extensionProfile && + scaleSet.virtualMachineProfile.extensionProfile.extensions ? + scaleSet.virtualMachineProfile.extensionProfile.extensions : []; + + if (!scaleSetExtensions.length) { + helpers.addResult(results, 2, 'No VMSS Extensions found', location, scaleSet.id); + } else { + let found = scaleSetExtensions.find(vmExt => vmExt.name && vmExt.name.toLowerCase() === 'iaasantimalware'); + if (found) { + helpers.addResult(results, 0, 'Windows Virtual Machine Scale Set has IaaS Antimalware extension installed', location, scaleSet.id); + } else { + helpers.addResult(results, 2, 'Windows Virtual Machine Scale Set does not have IaaS Antimalware extension installed', location, scaleSet.id); + } + } + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.spec.js b/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.spec.js new file mode 100644 index 0000000000..355f79e24d --- /dev/null +++ b/plugins/azure/virtualmachinescaleset/vmssWindowsAntiMalwareExt.spec.js @@ -0,0 +1,141 @@ +var expect = require('chai').expect; +var vmssWindowsAntiMalwareExt = require('./vmssWindowsAntiMalwareExt'); + +const virtualMachineScaleSets = [ + { + 'name': 'test-vmss', + 'id': '/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachineScaleSets/test-vmss', + 'type': 'Microsoft.Compute/virtualMachineScaleSets', + 'virtualMachineProfile': { + "storageProfile": { + "osDisk": { + "osType": "windows", + }, + }, + 'extensionProfile': { + 'extensions': [ + { + 'name': 'iaasantimalware', + 'properties': { + 'autoUpgradeMinorVersion': false, + 'publisher': 'Microsoft.ManagedServices', + 'type': 'AADSSHLoginForLinux', + 'typeHandlerVersion': '1.0', + } + } + ] + } + } + }, + { + 'name': 'test-vmss', + 'id': '/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachineScaleSets/test-vmss', + 'type': 'Microsoft.Compute/virtualMachineScaleSets', + 'virtualMachineProfile': { + "storageProfile": { + "osDisk": { + "osType": "windows", + }, + }, + 'extensionProfile': { + 'extensions': [ + { + 'name': 'AADLoginForWindows', + 'properties': { + 'autoUpgradeMinorVersion': false, + 'publisher': 'Microsoft.ManagedServices', + 'type': 'AADLoginForWindows', + 'typeHandlerVersion': '1.0', + } + } + ] + } + } + }, + { + 'name': 'test-vmss', + 'id': '/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.Compute/virtualMachineScaleSets/test-vmss', + 'type': 'Microsoft.Compute/virtualMachineScaleSets', + 'virtualMachineProfile': { + "storageProfile": { + "osDisk": { + "osType": "windows", + }, + }, + 'extensionProfile': { + 'extensions': [] + } + } + } +]; + +const createCache = (virtualMachineScaleSets) => { + let machine = {}; + if (virtualMachineScaleSets) { + machine['data'] = virtualMachineScaleSets; + } + return { + virtualMachineScaleSets: { + listAll: { + 'eastus': machine + } + } + }; +}; + +describe('vmssWindowsAntiMalwareExt', function() { + describe('run', function() { + it('should give passing result if no virtual machine scale sets', function(done) { + const cache = createCache([]); + vmssWindowsAntiMalwareExt.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(); + vmssWindowsAntiMalwareExt.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 windows Virtual Machine Scale Set has anti malware extension installed', function(done) { + const cache = createCache([virtualMachineScaleSets[0]]); + vmssWindowsAntiMalwareExt.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Windows Virtual Machine Scale Set has IaaS Antimalware extension installed'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + it('should give failing result if Virtual Machine Scale Set does not have anti malware extension installed', function(done) { + const cache = createCache([virtualMachineScaleSets[1]]); + vmssWindowsAntiMalwareExt.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Windows Virtual Machine Scale Set does not have IaaS Antimalware extension installed'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + it('should give failing result if no extensions installed', function(done) { + const cache = createCache([virtualMachineScaleSets[2]]); + vmssWindowsAntiMalwareExt.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('No VMSS Extensions found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file