Skip to content

Commit

Permalink
feature/AKD-115: Added Azure Cosmos DB 'Automatic Failover Enabled' p…
Browse files Browse the repository at this point in the history
…lugin and test cases (#578)

* Added Azure CosmosDB 'Advanced Threat Protection' plugin and test cases

* Added Azure Cosmos DB 'Automatic Failover Enabled' plugin and test cases
  • Loading branch information
AkhtarAmir authored Mar 26, 2021
1 parent b5793ea commit ecc0557
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 1 deletion.
5 changes: 5 additions & 0 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ var calls = {
listPostgres: {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.DBforPostgreSQL/servers?api-version=2017-12-01'
}
},
databaseAccounts: {
list: {
url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.DocumentDB/databaseAccounts?api-version=2020-06-01-preview'
}
}
};

Expand Down
2 changes: 2 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ module.exports = {
'kvRecoveryEnabled' : require(__dirname + '/plugins/azure/keyvaults/kvRecoveryEnabled.js'),
'keyExpirationEnabled' : require(__dirname + '/plugins/azure/keyvaults/keyExpirationEnabled.js'),
'secretExpirationEnabled' : require(__dirname + '/plugins/azure/keyvaults/secretExpirationEnabled.js'),

'automaticFailoverEnabled' : require(__dirname + '/plugins/azure/cosmosdb/automaticFailoverEnabled.js'),
},
github: {
'publicKeysRotated' : require(__dirname + '/plugins/github/users/publicKeysRotated.js'),
Expand Down
3 changes: 2 additions & 1 deletion helpers/azure/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,6 @@ module.exports = {
autoscaleSettings: locations,
resourceGroups: locations,
policyDefinitions: locations,
diagnosticSettingsOperations: ['global']
diagnosticSettingsOperations: ['global'],
databaseAccounts: locations
};
54 changes: 54 additions & 0 deletions plugins/azure/cosmosdb/automaticFailoverEnabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const async = require('async');
const helpers = require('../../../helpers/azure');

module.exports = {
title: 'Automatic Failover Enabled',
category: 'Cosmos DB',
description: 'Ensure that the Automatic Failover feature is enabled for Microsoft Azure Cosmos DB accounts.',
more_info: 'It is strongly recommended to configure the Azure Cosmos DB accounts used for production workloads to enable automatic failover. ' +
'Automatic failover allows Azure Cosmos DB to automatically failover to the Azure cloud region with the highest failover priority when the source region become unavailable.',
link: 'https://docs.microsoft.com/en-us/azure/cosmos-db/high-availability',
recommended_action: 'Modify Cosmos DB account to enable automatic failover.',
apis: ['databaseAccounts:list'],

run: function(cache, settings, callback) {
const results = [];
const source = {};
const locations = helpers.locations(settings.govcloud);

async.each(locations.databaseAccounts, function(location, rcb) {
var databaseAccounts = helpers.addSource(cache, source,
['databaseAccounts', 'list', location]);

if (!databaseAccounts) return rcb();

if (databaseAccounts.err || !databaseAccounts.data) {
helpers.addResult(results, 3,
'Unable to query for Cosmos DB accounts: ' + helpers.addError(databaseAccounts), location);
return rcb();
}

if (!databaseAccounts.data.length) {
helpers.addResult(results, 0, 'No Cosmos DB accounts found', location);
return rcb();
}


databaseAccounts.data.forEach(account => {
if (!account.id) return;

if (account.enableAutomaticFailover) {
helpers.addResult(results, 0,
'Automatic failover is enabled for Cosmos DB account', location, account.id);
} else {
helpers.addResult(results, 2,
'Automatic failover is not enabled for Cosmos DB account', location, account.id);
}
});

rcb();
}, function() {
callback(null, results, source);
});
}
};
129 changes: 129 additions & 0 deletions plugins/azure/cosmosdb/automaticFailoverEnabled.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
var expect = require('chai').expect;
var automaticFailoverEnabled = require('./automaticFailoverEnabled');

const databaseAccounts = [
{
"id": "/subscriptions/123/resourceGroups/tets-rg/providers/Microsoft.DocumentDB/databaseAccounts/aqua-cosmos",
"name": "aqua-cosmos",
"location": "East US",
"type": "Microsoft.DocumentDB/databaseAccounts",
"kind": "GlobalDocumentDB",
"provisioningState": "Succeeded",
"documentEndpoint": "https://aqua-cosmos.documents.azure.com:443/",
"publicNetworkAccess": "Enabled",
"enableAutomaticFailover": true,
"enableMultipleWriteLocations": false,
"enablePartitionKeyMonitor": false,
"isVirtualNetworkFilterEnabled": false,
"virtualNetworkRules": [],
"EnabledApiTypes": "Sql",
"disableKeyBasedMetadataWriteAccess": false,
"enableAnalyticalStorage": false,
"instanceId": "5f3e6edc-33c6-4a47-81aa-108af12d4fba",
"createMode": "Default",
"databaseAccountOfferType": "Standard"
},
{
"id": "/subscriptions/123/resourceGroups/tets-rg/providers/Microsoft.DocumentDB/databaseAccounts/aqua-cosmos",
"name": "aqua-cosmos",
"location": "East US",
"type": "Microsoft.DocumentDB/databaseAccounts",
"kind": "GlobalDocumentDB",
"provisioningState": "Succeeded",
"documentEndpoint": "https://aqua-cosmos.documents.azure.com:443/",
"publicNetworkAccess": "Enabled",
"enableAutomaticFailover": false,
"enableMultipleWriteLocations": false,
"enablePartitionKeyMonitor": false,
"isVirtualNetworkFilterEnabled": false,
"virtualNetworkRules": [],
"EnabledApiTypes": "Cassandra",
"disableKeyBasedMetadataWriteAccess": false,
"enableAnalyticalStorage": false,
"instanceId": "5f3e6edc-33c6-4a47-81aa-108af12d4fba",
"createMode": "Default",
"databaseAccountOfferType": "Standard"
}
];

const createCache = (accounts, accountsErr) => {
return {
databaseAccounts: {
list: {
'eastus': {
err: accountsErr,
data: accounts
}
}
}
}
};

describe('automaticFailoverEnabled', function() {
describe('run', function() {
it('should give passing result if no Cosmos DB accounts found', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('No Cosmos DB accounts found');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[]
);

automaticFailoverEnabled.run(cache, {}, callback);
});

it('should give passing result if automatic failover is enabled for Cosmos DB account', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Automatic failover is enabled for Cosmos DB account');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[databaseAccounts[0]]
);

automaticFailoverEnabled.run(cache, {}, callback);
});

it('should give failing result if automatic failover is not enabled for Cosmos DB account', function(done) {
const callback = (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Automatic failover is not enabled for Cosmos DB account');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[databaseAccounts[1]],
);

automaticFailoverEnabled.run(cache, {}, callback);
});

it('should give unknown result if unable to query for Cosmos DB accounts', function(done) {
const callback = (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 Cosmos DB accounts');
expect(results[0].region).to.equal('eastus');
done()
};

const cache = createCache(
[],
{ message: 'Unable to query Cosmos DB accounts'}
);

automaticFailoverEnabled.run(cache, {}, callback);
});
})
});

0 comments on commit ecc0557

Please sign in to comment.