Skip to content

Commit

Permalink
Merge branch 'master' into feature/AKD-191
Browse files Browse the repository at this point in the history
  • Loading branch information
giorod3 authored and AkhtarAmir committed Jun 1, 2021
2 parents 2cf101c + c586294 commit 205422e
Show file tree
Hide file tree
Showing 8 changed files with 610 additions and 0 deletions.
7 changes: 7 additions & 0 deletions collectors/azure/collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ var postcalls = {
url: 'https://management.azure.com/{id}/securityAlertPolicies?api-version=2017-03-01-preview'
}
},
failoverGroups: {
listByServer: {
reliesOnPath: 'servers.listSql',
properties: ['id'],
url: 'https://management.azure.com/{id}/failoverGroups?api-version=2017-03-01-preview'
}
},
serverAutomaticTuning: {
get: {
reliesOnPath: 'servers.listSql',
Expand Down
3 changes: 3 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ module.exports = {
'scaleSetMultiAz' : require(__dirname + '/plugins/azure/virtualmachines/scaleSetMultiAz.js'),
'scaleSetAutoscaleEnabled' : require(__dirname + '/plugins/azure/virtualmachines/scaleSetAutoscaleEnabled.js'),
'vmAvailabilitySetLimit' : require(__dirname + '/plugins/azure/virtualmachines/vmAvailabilitySetLimit.js'),
'premiumSsdDisabled' : require(__dirname + '/plugins/azure/virtualmachines/premiumSsdDisabled.js'),
'vmManagedDisks' : require(__dirname + '/plugins/azure/virtualmachines/vmManagedDisks.js'),
'autoInstanceRepairsEnabled' : require(__dirname + '/plugins/azure/virtualmachines/autoInstanceRepairsEnabled.js'),
'noEmptyScaleSets' : require(__dirname + '/plugins/azure/virtualmachines/noEmptyScaleSets.js'),
Expand Down Expand Up @@ -482,6 +483,7 @@ module.exports = {
'serverAuditingEnabled' : require(__dirname + '/plugins/azure/sqlserver/serverAuditingEnabled.js'),
'azureADAdminEnabled' : require(__dirname + '/plugins/azure/sqlserver/azureADAdminEnabled.js'),
'sqlServerTlsVersion' : require(__dirname + '/plugins/azure/sqlserver/sqlServerTlsVersion.js'),
'autoFailoverGroupsEnabled' : require(__dirname + '/plugins/azure/sqlserver/autoFailoverGroupsEnabled.js'),
'automaticTuningEnabled' : require(__dirname + '/plugins/azure/sqlserver/automaticTuningEnabled.js'),

'javaVersion' : require(__dirname + '/plugins/azure/appservice/javaVersion.js'),
Expand All @@ -495,6 +497,7 @@ module.exports = {
'httpsOnlyEnabled' : require(__dirname + '/plugins/azure/appservice/httpsOnlyEnabled.js'),
'tlsVersionCheck' : require(__dirname + '/plugins/azure/appservice/tlsVersionCheck.js'),
'appserviceAutomatedBackups' : require(__dirname + '/plugins/azure/appservice/appserviceAutomatedBackups.js'),
'alwaysOnEnabled' : require(__dirname + '/plugins/azure/appservice/alwaysOnEnabled.js'),

'rbacEnabled' : require(__dirname + '/plugins/azure/kubernetesservice/rbacEnabled.js'),
'aksLatestVersion' : require(__dirname + '/plugins/azure/kubernetesservice/aksLatestVersion.js'),
Expand Down
64 changes: 64 additions & 0 deletions plugins/azure/appservice/alwaysOnEnabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
var async = require('async');
var helpers = require('../../../helpers/azure');

module.exports = {
title: 'Web Apps Always On Enabled',
category: 'App Service',
description: 'Ensures that Azure Web Apps have Always On feature enabled.',
more_info: 'Always On feature keeps the app loaded even when there\'s no traffic. It\'s required for continuous WebJobs or for WebJobs that are triggered using a CRON expression.',
recommended_action: 'Enable Always On feature for Azure Web Apps',
link: 'https://docs.microsoft.com/en-us/azure/app-service/configure-common',
apis: ['webApps:list', 'webApps:listConfigurations'],

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

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

if (!webApps) return rcb();

if (webApps.err || !webApps.data) {
helpers.addResult(results, 3, 'Unable to query for Web Apps: ' + helpers.addError(webApps), location);
return rcb();
}

if (!webApps.data.length) {
helpers.addResult(results, 0, 'No existing Web Apps found', location);
return rcb();
}

async.each(webApps.data, function(webApp, scb) {
if (webApp && webApp.kind && webApp.kind === 'functionapp') {
helpers.addResult(results, 0, 'Always On feature can not be configured for the function App', location, webApp.id);
return scb();
}

const configs = helpers.addSource(cache, source,
['webApps', 'listConfigurations', location, webApp.id]);

if (!configs || configs.err || !configs.data || !configs.data.length) {
helpers.addResult(results, 3, 'Unable to query for Web App Configs: ' + helpers.addError(configs), location);
return scb();
}

const alwaysOnEnabled = configs.data.some(config => config.alwaysOn);
if (alwaysOnEnabled) {
helpers.addResult(results, 0, 'Always On feature is enabled for the Web App', location, webApp.id);
} else {
helpers.addResult(results, 2, 'Always On feature is disabled for the Web App', location, webApp.id);
}

scb();
}, function() {
rcb();
});
}, function() {
// Global checking goes here
callback(null, results, source);
});
}
};
143 changes: 143 additions & 0 deletions plugins/azure/appservice/alwaysOnEnabled.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
var expect = require('chai').expect;
var alwaysOnEnabled = require('./alwaysOnEnabled');

const webApps = [
{
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app',
'name': 'test-app',
'type': 'Microsoft.Web/sites',
'kind': 'app,linux',
'location': 'East US'
},
{
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app',
'name': 'test-app',
'type': 'Microsoft.Web/sites',
'kind': 'functionapp',
'location': 'East US'
}
];

const configs = [
{
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app',
'name': 'test-app',
'type': 'Microsoft.Web/sites',
'location': 'East US',
'alwaysOn': true
},
{
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Web/sites/test-app',
'name': 'test-app',
'type': 'Microsoft.Web/sites',
'location': 'East US',
'alwaysOn': false
}
];

const createCache = (webApps, configs) => {
let app = {};
let config = {};

if (webApps) {
app['data'] = webApps;
if (webApps && webApps.length) {
config[webApps[0].id] = {
'data': configs
};
}
}

return {
webApps: {
list: {
'eastus': app
},
listConfigurations: {
'eastus': config
}
}
};
};

describe('alwaysOnEnabled', function() {
describe('run', function() {
it('should give passing result if no web apps', function(done) {
const cache = createCache([]);
alwaysOnEnabled.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 Web Apps found');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give unknown result if unable to query for web apps', function(done) {
const cache = createCache();
alwaysOnEnabled.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 Web Apps');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give passing result if always on can not be configured', function(done) {
const cache = createCache([webApps[1]], []);
alwaysOnEnabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Always On feature can not be configured for the function App');
expect(results[0].region).to.equal('eastus');
done();
});
});


it('should give unknown result if no web app configs', function(done) {
const cache = createCache([webApps[0]], []);
alwaysOnEnabled.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 Web App Configs:');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give unknown result if unable to query for web app configs', function(done) {
const cache = createCache([webApps[0]]);
alwaysOnEnabled.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 Web App Configs:');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give passing result if always on is enabled', function(done) {
const cache = createCache([webApps[0]], [configs[0]]);
alwaysOnEnabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Always On feature is enabled for the Web App');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if always on is disabled', function(done) {
const cache = createCache([webApps[0]], [configs[1]]);
alwaysOnEnabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Always On feature is disabled for the Web App');
expect(results[0].region).to.equal('eastus');
done();
});
});
});
});
59 changes: 59 additions & 0 deletions plugins/azure/sqlserver/autoFailoverGroupsEnabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
var async = require('async');
const helpers = require('../../../helpers/azure');

module.exports = {
title: 'Auto-Failover Groups Enabled',
category: 'SQL Server',
description: 'Ensures that auto-failover groups are configured for Azure SQL database servers.',
more_info: 'In case of any outage that impacts one or more SQL databases, automatic failover process switches all secondary databases in the group to primary databases to ensure high availability.',
recommended_action: 'Ensure that auto-failover Groups are configured for Azure SQL database servers',
link: 'https://docs.microsoft.com/en-us/azure/azure-sql/database/auto-failover-group-overview',
apis: ['servers:listSql', 'failoverGroups:listByServer'],

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

async.each(locations.servers, function(location, rcb) {

const servers = helpers.addSource(cache, source,
['servers', 'listSql', location]);

if (!servers) return rcb();

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

if (!servers.data.length) {
helpers.addResult(results, 0, 'No SQL servers found', location);
return rcb();
}

for (const server of servers.data) {
const failoverGroups = helpers.addSource(cache, source,
['failoverGroups', 'listByServer', location, server.id]);

if (!failoverGroups || failoverGroups.err || !failoverGroups.data) {
helpers.addResult(results, 3,
'Unable to query for auto-failover groups: ' + helpers.addError(failoverGroups), location, server.id);
continue;
}

if (failoverGroups.data.length) {
helpers.addResult(results, 0, 'Auto-failover groups are configured for the SQL server', location, server.id);
} else {
helpers.addResult(results, 2, 'Auto-failover groups are not configured for the SQL server', location, server.id);
}
}

rcb();
}, function() {
// Global checking goes here
callback(null, results, source);
});
}
};
Loading

0 comments on commit 205422e

Please sign in to comment.