Skip to content

Commit

Permalink
Azure/gov cloud (#2021)
Browse files Browse the repository at this point in the history
* Azure/Gov-Cloud

* removed extra line

* fixed-spell

* linting

* lint

* Azure/Gov-Cloud

* Azure/Gov-Cloud

* Azure/Gov-Cloud

* Azure/Gov-Cloud
  • Loading branch information
alphadev4 committed May 24, 2024
1 parent c2063f9 commit 74a3d05
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 22 deletions.
6 changes: 4 additions & 2 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ let collect = function(AzureConfig, settings, callback) {
helpers.call({
url: localUrl,
post: obj.post,
token: obj.graph ? loginData.graphToken : (obj.vault ? loginData.vaultToken : loginData.token)
token: obj.graph ? loginData.graphToken : (obj.vault ? loginData.vaultToken : loginData.token),
govcloud : AzureConfig.Govcloud
}, function(err, data) {
if (err) return cb(err);

Expand Down Expand Up @@ -143,7 +144,8 @@ let collect = function(AzureConfig, settings, callback) {
function(cb) {
function processTopCall(collectionObj, service, subCallObj, subCallCb) {
processCall(subCallObj, function(processCallErr, processCallData) {
helpers.addLocations(subCallObj, service, collectionObj, processCallErr, processCallData , skip_locations);
if (AzureConfig.Govcloud) helpers.addGovLocations(subCallObj, service, collectionObj, processCallErr, processCallData , skip_locations);
else helpers.addLocations(subCallObj, service, collectionObj, processCallErr, processCallData , skip_locations);
subCallCb();
});
}
Expand Down
5 changes: 4 additions & 1 deletion config_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ module.exports = {
// application_id: process.env.AZURE_APPLICATION_ID || '',
// key_value: process.env.AZURE_KEY_VALUE || '',
// directory_id: process.env.AZURE_DIRECTORY_ID || '',
// subscription_id: process.env.AZURE_SUBSCRIPTION_ID || ''
// subscription_id: process.env.AZURE_SUBSCRIPTION_ID || '',
// storage_connection: process.env.AZURE_STORAGE_CONNECTION || '',
// blob_container: process.env.AZURE_BLOB_CONTAINER || '',
// govcloud: process.env.AZURE_GOV_CLOUD || ''
},
azure_remediate: {
// OPTION 1: If using a credential JSON file, enter the path below
Expand Down
40 changes: 38 additions & 2 deletions engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var exports = require('./exports.js');
var suppress = require('./postprocess/suppress.js');
var output = require('./postprocess/output.js');
var azureHelper = require('./helpers/azure/auth.js');
var azureStorage = require('@azure/storage-blob');

function runAuth(settings, remediateConfig, callback) {
if (settings.cloud && settings.cloud == 'azure') {
Expand All @@ -13,6 +14,34 @@ function runAuth(settings, remediateConfig, callback) {
});
} else callback();
}

async function uploadResultsToBlob(resultsObject, storageConnection, blobContainerName ) {
try {
const blobServiceClient = azureStorage.BlobServiceClient.fromConnectionString(storageConnection);
const containerClient = blobServiceClient.getContainerClient(blobContainerName);

// Check if the container exists, if not, create it
const exists = await containerClient.exists();
if (!exists) {
await containerClient.create();
console.log(`Container ${blobContainerName} created successfully.`);
}

const blobName = `results-${Date.now()}.json`;
const blockBlobClient = containerClient.getBlockBlobClient(blobName);

const data = JSON.stringify(resultsObject, null, 2);
const uploadBlobResponse = await blockBlobClient.upload(data, data.length);
console.log(`Blob ${blobName} uploaded successfully. Request ID: ${uploadBlobResponse.requestId}`);
} catch (error) {
if (error.message && error.message == 'Invalid DefaultEndpointsProtocol') {
console.log(`Invalid Storage Account connection string ${error.message}`);
} else {
console.log(`Failed to upload results to blob: ${error.message}`);
}
}
}

/**
* The main function to execute CloudSploit scans.
* @param cloudConfig The configuration for the cloud provider.
Expand Down Expand Up @@ -148,23 +177,28 @@ var engine = function(cloudConfig, settings) {
console.log('INFO: Analysis complete. Scan report to follow...');

var maximumStatus = 0;

var resultsObject = {}; // Initialize resultsObject for azure gov cloud

function executePlugins(cloudRemediateConfig) {
async.mapValuesLimit(plugins, 10, function(plugin, key, pluginDone) {
if (skippedPlugins.indexOf(key) > -1) return pluginDone(null, 0);

var postRun = function(err, results) {
if (err) return console.log(`ERROR: ${err}`);
if (!results || !results.length) {
console.log(`Plugin ${plugin.title} returned no results. There may be a problem with this plugin.`);
} else {
if (!resultsObject[plugin.title]) {
resultsObject[plugin.title] = [];
}
for (var r in results) {
// If we have suppressed this result, then don't process it
// so that it doesn't affect the return code.
if (suppressionFilter([key, results[r].region || 'any', results[r].resource || 'any'].join(':'))) {
continue;
}

resultsObject[plugin.title].push(results[r]);

var complianceMsg = [];
if (settings.compliance && settings.compliance.length) {
settings.compliance.forEach(function(c) {
Expand Down Expand Up @@ -224,6 +258,8 @@ var engine = function(cloudConfig, settings) {
}
}, function(err) {
if (err) return console.log(err);

if (cloudConfig.StorageConnection && cloudConfig.BlobContainer) uploadResultsToBlob(resultsObject, cloudConfig.StorageConnection, cloudConfig.BlobContainer);
// console.log(JSON.stringify(collection, null, 2));
outputHandler.close();
if (settings.exit_code) {
Expand Down
72 changes: 58 additions & 14 deletions helpers/azure/auth.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var request = require('request');
var locations = require(__dirname + '/locations.js');
var locations_gov = require(__dirname + '/locations_gov.js');

var dontReplace = {
'type': {
Expand Down Expand Up @@ -58,22 +59,39 @@ module.exports = {
});
}

// First, login without audience
performLogin(null, function(err, credentials) {
if (err) return callback(err);
performLogin({ tokenAudience: 'https://graph.microsoft.com' }, function(graphErr, graphCredentials) {
if (graphErr) return callback(graphErr);
performLogin({ tokenAudience: 'https://vault.azure.net' }, function(vaultErr, vaultCredentials) {
if (vaultErr) return callback(vaultErr);
callback(null, {
environment: credentials.environment,
token: credentials.tokenCache._entries[0].accessToken,
graphToken: graphCredentials.tokenCache._entries[0].accessToken,
vaultToken: vaultCredentials.tokenCache._entries[0].accessToken
if (azureConfig.Govcloud) {
performLogin({ environment: msRestAzure.AzureEnvironment.AzureUSGovernment }, function(err, credentials) {
if (err) return callback(err);
performLogin({ tokenAudience: 'https://graph.microsoft.us', environment: msRestAzure.AzureEnvironment.AzureUSGovernment }, function(graphErr, graphCredentials) {
if (graphErr) return callback(graphErr);
performLogin({ tokenAudience: 'https://vault.azure.us', environment: msRestAzure.AzureEnvironment.AzureUSGovernment }, function(vaultErr, vaultCredentials) {
if (vaultErr) console.log('No vault');
callback(null, {
environment: credentials.environment,
token: credentials.tokenCache._entries[0].accessToken,
graphToken: graphCredentials ? graphCredentials.tokenCache._entries[0].accessToken : null,
vaultToken: vaultCredentials ? vaultCredentials.tokenCache._entries[0].accessToken : null
});
});
});
});
});
} else {
performLogin(null, function(err, credentials) {
if (err) return callback(err);
performLogin({ tokenAudience: 'https://graph.microsoft.com' }, function(graphErr, graphCredentials) {
if (graphErr) return callback(graphErr);
performLogin({ tokenAudience: 'https://vault.azure.net' }, function(vaultErr, vaultCredentials) {
if (vaultErr) return callback(vaultErr);
callback(null, {
environment: credentials.environment,
token: credentials.tokenCache._entries[0].accessToken,
graphToken: graphCredentials.tokenCache._entries[0].accessToken,
vaultToken: vaultCredentials.tokenCache._entries[0].accessToken
});
});
});
});
}
},

call: function(params, callback) {
Expand All @@ -86,6 +104,9 @@ module.exports = {
headers['Content-Type'] = 'application/json;charset=UTF-8';
}

if (params.govcloud) params.url = params.url.replace('management.azure.com', 'management.usgovcloudapi.net');


request({
method: params.method ? params.method : params.post ? 'POST' : 'GET',
uri: params.url,
Expand Down Expand Up @@ -155,7 +176,7 @@ module.exports = {
});
},

addLocations: function(obj, service, collection, err, data , skip_locations) {
addLocations: function(obj, service, collection, err, data, skip_locations) {
if (!service || !locations[service]) return;
locations[service].forEach(function(location) {
if (skip_locations.includes(location)) return;
Expand All @@ -178,6 +199,29 @@ module.exports = {
}
});
},
addGovLocations: function(obj, service, collection, err, data , skip_locations) {
if (!service || !locations_gov[service]) return;
locations_gov[service].forEach(function(location) {
if (skip_locations.includes(location)) return;
collection[location.toLowerCase()] = {};
if (err) {
collection[location.toLowerCase()].err = err;
} else if (data) {
if (data.value && Array.isArray(data.value)) {
collection[location.toLowerCase()].data = data.value.filter(function(dv) {
if (dv.location &&
dv.location.toLowerCase().replace(/ /g, '') == location.toLowerCase()) {
return true;
} else if (location.toLowerCase() == 'global' && (!dv.location || obj.ignoreLocation)) {
return true;
}
return false;
});
reduceProperties(service, collection[location.toLowerCase()].data);
}
}
});
},

reduceProperties: reduceProperties
};
76 changes: 75 additions & 1 deletion helpers/azure/locations_gov.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,79 @@ var locations = [
];

module.exports = {
all: locations
all: locations,
resources: locations,
storageAccounts: ['global'],
virtualMachines: locations,
snapshots: locations,
disks: locations,
activityLogAlerts: ['global'],
vaults: locations,
policyAssignments: locations.concat(['global']),
recoveryServiceVaults: locations,
backupPolicies: locations,
backupProtectedItems: locations,
webApps: locations,
appServiceCertificates: locations,
networkSecurityGroups: locations,
servers: locations,
logProfiles: ['global'],
profiles: ['global'],
managementLocks: ['global'],
blobServices: locations,
networkWatchers: locations,
networkInterfaces: locations,
managedClusters: locations,
virtualMachineScaleSets: locations,
autoProvisioningSettings: ['global'],
securityContacts: ['global'],
usages: ['global'],
subscriptions: ['global'],
loadBalancers: locations,
availabilitySets: locations,
virtualNetworks: locations,
virtualNetworkPeerings: locations,
virtualNetworkGateways: locations,
networkGatewayConnections: locations,
natGateways: locations,
users: ['global'],
registries: locations,
redisCaches: locations,
pricings: ['global'],
roleDefinitions: ['global'],
aad: ['global'],
groups: ['global'],
servicePrincipals: ['global'],
autoscaleSettings: locations,
resourceGroups: locations,
policyDefinitions: locations,
diagnosticSettingsOperations: ['global'],
databaseAccounts: locations,
securityCenter: ['global'],
advisor: ['global'],
publicIPAddresses: locations,
privateDnsZones: ['global'],
privateEndpoints: locations,
securityContactv2: ['global'],
images: locations,
vmScaleSet: locations,
applicationGateway: locations,
wafPolicies: locations,
routeTables: locations,
bastionHosts: locations,
applications: ['global'],
eventGrid: locations,
eventHub: locations,
mediaServices: locations,
serviceBus: locations,
classicFrontDoors: ['global'],
afdWafPolicies: ['global'],
appConfigurations: locations,
automationAccounts: locations,
openAI: locations,
logAnalytics: locations,
publicIpAddresses: locations,
computeGalleries: locations,
databricks: locations,
containerApps: locations
};
5 changes: 4 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ if (config.credentials.aws.credential_file && (!settings.cloud || (settings.clou
KeyValue: config.credentials.azure.key_value,
DirectoryID: config.credentials.azure.directory_id,
SubscriptionID: config.credentials.azure.subscription_id,
location: 'East US'
location: 'East US',
Govcloud: config.credentials.azure.govcloud,
StorageConnection: config.credentials.azure.storage_connection,
BlobContainer: config.credentials.azure.blob_container
};
} else if (config.credentials.google.credential_file && (!settings.cloud || (settings.cloud == 'google'))) {
settings.cloud = 'google';
Expand Down
2 changes: 1 addition & 1 deletion plugins/aws/ec2/overutilizedEC2Instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = {
settings: {
ec2_cpu_threshold_fail: {
name: 'EC2 CPU Threshold Fail',
description: 'Return a failing result when consumed EC2 insatnce cpu threshold equals or exceeds this percentage',
description: 'Return a failing result when consumed EC2 instance cpu threshold equals or exceeds this percentage',
regex: '^(100|[1-9][0-9]?)$',
default: '90'
}
Expand Down

0 comments on commit 74a3d05

Please sign in to comment.