Skip to content

Commit

Permalink
azure function and plugin updates
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewdfuller committed Jul 24, 2020
1 parent 99e5f6a commit f69581a
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 37 deletions.
18 changes: 13 additions & 5 deletions helpers/azure/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,22 @@ module.exports = {
},

call: function(params, callback) {
var headers = {
'Authorization': `Bearer ${params.token}`
};

if (params.body && Object.keys(params.body).length) {
headers['Content-Length'] = JSON.stringify(params.body).length;
headers['Content-Type'] = 'application/json;charset=UTF-8';
}

request({
method: params.post ? 'POST' : 'GET',
method: params.method ? params.method : params.post ? 'POST' : 'GET',
uri: params.url,
headers: {
'Authorization': `Bearer ${params.token}`
}
headers: headers,
body: params.body ? JSON.stringify(params.body) : null
}, function(error, response, body) {
if (response && response.statusCode == 200 && body) {
if (response && response.statusCode === 200 && body) {
try {
body = JSON.parse(body);
} catch (e) {
Expand Down
51 changes: 43 additions & 8 deletions helpers/azure/functions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var shared = require(__dirname + '/../shared.js');
var auth = require(__dirname + '/auth.js');

function addResult(results, status, message, region, resource, custom) {
// Override unknown results for known error messages
Expand Down Expand Up @@ -41,7 +42,7 @@ function addResult(results, status, message, region, resource, custom) {

function findOpenPorts(ngs, protocols, service, location, results) {
let found = false;
var openPrefix = ['*', '0.0.0.0', '<nw/0>', '/0', 'internet'];
var openPrefix = ['*', '0.0.0.0', '0.0.0.0/0', '<nw/0>', '/0', '::/0', 'internet'];
for (let sGroups of ngs) {
let strings = [];
let resource = sGroups.id;
Expand Down Expand Up @@ -73,28 +74,28 @@ function findOpenPorts(ngs, protocols, service, location, results) {
securityRule.properties['direction'] &&
securityRule.properties['direction'] === 'Inbound' &&
securityRule.properties['protocol'] &&
securityRule.properties['protocol'] === protocol) {
(securityRule.properties['protocol'] === protocol || securityRule.properties['protocol'] === '*')) {
if (securityRule.properties['destinationPortRange']) {
if (securityRule.properties['destinationPortRange'].toString().indexOf("-") > -1) {
let portRange = securityRule.properties['destinationPortRange'].split("-");
let startPort = portRange[0];
let endPort = portRange[1];
if (parseInt(startPort) < port && parseInt(endPort) > port) {
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol == '*' ? `All protocols` : protocol.toUpperCase()) +
if (parseInt(startPort) <= port && parseInt(endPort) >= port) {
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol === '*' ? `All protocols` : protocol.toUpperCase()) +
` port ` + ports + ` open to ` + sourceFilter;
strings.push(string);
if (strings.indexOf(string) === -1) strings.push(string);
found = true;
}
} else if (securityRule.properties['destinationPortRange'].toString().indexOf(port) > -1) {
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol == '*' ? `All protocols` : protocol.toUpperCase()) +
(ports == '*' ? ` and all ports` : ` port ` + ports) + ` open to ` + sourceFilter;
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol === '*' ? `All protocols` : protocol.toUpperCase()) +
(ports === '*' ? ` and all ports` : ` port ` + ports) + ` open to ` + sourceFilter;
if (strings.indexOf(string) === -1) strings.push(string);
found = true;
}
} else if (securityRule.properties['destinationPortRanges'] &&
securityRule.properties['destinationPortRanges'].toString().indexOf(port) > -1) {
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol == '*' ? `All protocols` : protocol.toUpperCase()) +
var string = `Security Rule "` + securityRule['name'] + `": ` + (protocol === '*' ? `All protocols` : protocol.toUpperCase()) +
` port ` + ports + ` open to ` + sourceFilter;
if (strings.indexOf(string) === -1) strings.push(string);
found = true;
Expand Down Expand Up @@ -300,11 +301,45 @@ function checkServerConfigs(servers, cache, source, location, results, serverTyp
});
}

function processCall(config, method, body, baseUrl, resource, callback) {
var fullUrl = baseUrl.replace('{resource}', resource);

var params = {
url: fullUrl,
body: body,
token: config.token,
method: method
};

auth.call(params, callback);
}

function remediatePlugin(config, method, body, baseUrl, resource, remediation_file, putCall, pluginName, callback) {
processCall(config, method, body, baseUrl, resource, function(err) {
if (err) {
remediation_file['remediate']['actions'][pluginName]['error'] = err;
return callback(err, null);
}

let action = body;
action.action = putCall;

remediation_file['post_remediate']['actions'][pluginName][resource] = action;
remediation_file['remediate']['actions'][pluginName][resource] = {
'Action': 'Enabled'
};

return callback(null, action);
})
}

module.exports = {
addResult: addResult,
findOpenPorts: findOpenPorts,
checkPolicyAssignment: checkPolicyAssignment,
checkLogAlerts: checkLogAlerts,
checkAppVersions: checkAppVersions,
checkServerConfigs: checkServerConfigs
checkServerConfigs: checkServerConfigs,
remediatePlugin: remediatePlugin,
processCall: processCall
};
6 changes: 6 additions & 0 deletions plugins/azure/storageaccounts/networkAccessDefaultAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ module.exports = {
for (var acct in storageAccount.data) {
const account = storageAccount.data[acct];

// Different versions of the Azure API return different response
// formats for this property, hence the extra check.
if (account.networkRuleSet &&
account.networkRuleSet.defaultAction &&
account.networkRuleSet.defaultAction.toLowerCase() === 'deny') {
helpers.addResult(results, 0, 'Storage Account default network access rule set to deny', location, account.id);
} else if (account.networkAcls &&
account.networkAcls.defaultAction &&
account.networkAcls.defaultAction.toLowerCase() === 'deny') {
helpers.addResult(results, 0, 'Storage Account default network access rule set to deny', location, account.id);
} else {
helpers.addResult(results, 2, 'Storage Account default network access rule set to allow from all networks', location, account.id);
}
Expand Down
37 changes: 35 additions & 2 deletions plugins/azure/storageaccounts/storageAccountsHttps.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
var async = require('async');

var helpers = require('../../../helpers/azure/');
var helpers = require('../../../helpers/azure');

module.exports = {
title: 'Storage Accounts HTTPS',
Expand All @@ -10,6 +9,11 @@ module.exports = {
recommended_action: 'Enable the HTTPS-only option for all Storage Accounts.',
link: 'https://docs.microsoft.com/en-us/azure/governance/policy/samples/ensure-https-storage-account',
apis: ['storageAccounts:list'],
remediation_min_version: '202006260310',
remediation_description: 'The HTTPS-only option will be enabled for the storage account',
apis_remediate: ['storageAccounts:list'],
actions: {remediate:['storageAccounts:update'], rollback:['storageAccounts:update']},
permissions: {remediate: ['storageAccounts:update'], rollback: ['storageAccounts:update']},
compliance: {
hipaa: 'HIPAA requires all data to be transmitted over secure channels. ' +
'Storage Account HTTPS should be used to ensure all data access ' +
Expand Down Expand Up @@ -54,5 +58,34 @@ module.exports = {
// Global checking goes here
callback(null, results, source);
});
},
remediate: function(config, cache, settings, resource, callback) {
var remediation_file = settings.remediation_file;
var putCall = this.actions.remediate;

// inputs specific to the plugin
var pluginName = 'storageAccountsHttps';
var baseUrl = 'https://management.azure.com/{resource}?api-version=2019-06-01';
var method = 'PATCH';

// for logging purposes
var storageAccountNameArr = resource.split('/');
var storageAccountName = storageAccountNameArr[storageAccountNameArr.length - 1];

// create the params necessary for the remediation
var body = {
'properties': {
'supportsHttpsTrafficOnly': true
}

};

// logging
remediation_file['pre_remediate']['actions'][pluginName][resource] = {
'enableHttpsTrafficOnly': 'Disabled',
'storageAccount': storageAccountName
};

helpers.remediatePlugin(config, method, body, baseUrl, resource, remediation_file, putCall, pluginName, callback);
}
};
58 changes: 36 additions & 22 deletions plugins/azure/virtualmachines/vmEndpointProtection.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,35 +37,49 @@ module.exports = {
helpers.addResult(results, 0, 'No Virtual Machines found', location);
} else {
virtualMachines.data.forEach(function(virtualMachine){
var windowsImg = false;
if (virtualMachine.storageProfile &&
virtualMachine.storageProfile.imageReference &&
virtualMachine.storageProfile.imageReference.offer &&
virtualMachine.storageProfile.imageReference.offer.toLowerCase().indexOf('windowsserver') > -1) {
helpers.addResult(results, 0, 'The Microsoft VM does not offer endpoint protection', location, virtualMachine.id);
} else {
var virtualMachineExtensions = helpers.addSource(cache, source,
['virtualMachineExtensions', 'list', location, virtualMachine.id]);

if (!virtualMachineExtensions || virtualMachineExtensions.err || !virtualMachineExtensions.data) {
helpers.addResult(results, 3, 'Unable to query for VM Extensions: ' + helpers.addError(virtualMachineExtensions), location, virtualMachine.id);
} else if (!virtualMachineExtensions.data.length) {
windowsImg = true;
} else if (virtualMachine.storageProfile &&
virtualMachine.storageProfile.osDisk &&
virtualMachine.storageProfile.osDisk.osType &&
virtualMachine.storageProfile.osDisk.osType.toLowerCase().indexOf('windows') > -1) {
windowsImg = true;
}

var virtualMachineExtensions = helpers.addSource(cache, source,
['virtualMachineExtensions', 'list', location, virtualMachine.id]);

if (!virtualMachineExtensions || virtualMachineExtensions.err || !virtualMachineExtensions.data) {
helpers.addResult(results, 3, 'Unable to query for VM Extensions: ' + helpers.addError(virtualMachineExtensions), location, virtualMachine.id);
} else if (!virtualMachineExtensions.data.length) {
if (!windowsImg) {
helpers.addResult(results, 2, 'No VM Extensions found', location, virtualMachine.id);
} else {
var antiMalware = false;
virtualMachineExtensions.data.forEach(function(virtualMachineExtension){
if (virtualMachineExtension.type &&
virtualMachineExtension.type == 'IaaSAntimalware' &&
virtualMachineExtension.settings &&
virtualMachineExtension.settings.AntimalwareEnabled &&
virtualMachineExtension.settings.AntimalwareEnabled == 'true') {
antiMalware = true;
}
});

if (antiMalware) {
helpers.addResult(results, 0, 'Endpoint protection is installed on the virtual machine', location, virtualMachine.id);
} else {
helpers.addResult(results, 0, 'The Microsoft VM does not offer endpoint protection', location, virtualMachine.id);
}
} else {
var antiMalware = false;
virtualMachineExtensions.data.forEach(function(virtualMachineExtension) {
if (virtualMachineExtension.type &&
virtualMachineExtension.type == 'IaaSAntimalware' &&
virtualMachineExtension.settings &&
virtualMachineExtension.settings.AntimalwareEnabled &&
virtualMachineExtension.settings.AntimalwareEnabled) {
antiMalware = true;
}
});

if (antiMalware) {
helpers.addResult(results, 0, 'Endpoint protection is installed on the virtual machine', location, virtualMachine.id);
} else {
if (!windowsImg) {
helpers.addResult(results, 2, 'Endpoint protection is not installed on the virtual machine', location, virtualMachine.id);
} else {
helpers.addResult(results, 0, 'The Microsoft VM does not offer endpoint protection', location, virtualMachine.id);
}
}
}
Expand Down

0 comments on commit f69581a

Please sign in to comment.