Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable defender for sql servers #2102

Merged
merged 3 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 76 additions & 12 deletions plugins/azure/defender/enableDefenderForSqlServers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,103 @@ module.exports = {
category: 'Defender',
domain: 'Management and Governance',
severity: 'High',
description: 'Ensures that Microsoft Defender is enabled for Azure SQL Server Databases.',
description: 'Ensures that Microsoft Defender is enabled for Azure SQL Server Databases at subscription level or individual resource level.',
more_info: 'Turning on Microsoft Defender for Azure SQL Server Databases enables threat detection for Azure SQL database servers, providing threat intelligence, anomaly detection, and behavior analytics in the Microsoft Defender for Cloud.',
recommended_action: 'Turning on Microsoft Defender for Azure SQL Databases incurs an additional cost per resource.',
link: 'https://learn.microsoft.com/en-us/azure/security-center/security-center-detection-capabilities',
apis: ['pricings:list'],
realtime_triggers: ['microsoftsecurity:pricings:write','microsoftsecurity:pricings:delete'],
apis: ['pricings:list', 'servers:listSql', 'serverSecurityAlertPolicies:listByServer'],
settings: {
check_level: {
name: 'Defender Check Level',
description: 'Check for Defender at subscription level or resource level',
regex: '^(subscription|resource)$',
default: 'subscription'
}
},
realtime_triggers: ['microsoftsecurity:pricings:write','microsoftsecurity:pricings:delete','microsoftsql:servers:securityalertpolicies:write'],

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

async.each(locations.pricings, function(location, rcb) {
var pricings = helpers.addSource(cache, source,
['pricings', 'list', location]);
var config = {
check_level: settings.check_level || this.settings.check_level.default
};

if (!pricings) return rcb();
var serviceName = 'sqlservers';
var serviceDisplayName = 'SQL Servers';


if (config.check_level === 'subscription') {
var pricings = helpers.addSource(cache, source, ['pricings', 'list', 'global']);

if (!pricings) return callback(null, results, source);

if (pricings.err || !pricings.data) {
helpers.addResult(results, 3,
'Unable to query for Pricing: ' + helpers.addError(pricings), location);
return rcb();
'Unable to query Pricing information: ' + helpers.addError(pricings), 'global');
return callback(null, results, source);
}

if (!pricings.data.length) {
helpers.addResult(results, 0, 'No Pricing information found', location);
helpers.addResult(results, 0, 'No Pricing information found', 'global');
return callback(null, results, source);
}


let pricingData = pricings.data.find((pricing) => pricing.name.toLowerCase() === serviceName);
alphadev4 marked this conversation as resolved.
Show resolved Hide resolved

if (pricingData && pricingData.pricingTier && pricingData.pricingTier.toLowerCase() === 'standard') {
helpers.addResult(results, 0,
`Azure Defender is enabled for ${serviceDisplayName} at subscription level`, 'global', pricingData.id);
} else {
helpers.addResult(results, 2,
`Azure Defender is not enabled for ${serviceDisplayName} at subscription level`, 'global');
}
return callback(null, results, source);
}

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();
}

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

servers.data.forEach(server => {
const securitySettings = helpers.addSource(cache, source,
['serverSecurityAlertPolicies', 'listByServer', location, server.id]);

if (!securitySettings || securitySettings.err || !securitySettings.data) {
helpers.addResult(results, 3,
'Unable to query for SQL server security alert policies: ' + helpers.addError(securitySettings),
location, server.id);
} else {
securitySettings.data.forEach(setting => {
if (setting.state && setting.state.toLowerCase() === 'enabled') {
helpers.addResult(results, 0,
'Azure Defender is enabled for SQL server', location, server.id);
} else {
helpers.addResult(results, 2,
'Azure Defender is not enabled for SQL server', location, server.id);
}
});
}
});

rcb();
}, function(){
}, function() {
callback(null, results, source);
});
}
Expand Down
178 changes: 109 additions & 69 deletions plugins/azure/defender/enableDefenderForSqlServers.spec.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,127 @@
var assert = require('assert');
var expect = require('chai').expect;
var auth = require('./enableDefenderForSqlServers');
const assert = require('assert');
const expect = require('chai').expect;
const plugin = require('./enableDefenderForSqlServers');

const createCache = (err, data) => {
return {
pricings: {
list: {
'global': {
err: err,
data: data
}
}
}
}
};

describe('enableDefenderForSqlDatabases', function() {
describe('enableDefenderForSqlServers', function() {
describe('run', function() {
it('should give passing result if no pricings 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 Pricing information found');
expect(results[0].region).to.equal('global');
done()
it('should give passing result if Defender is enabled at subscription level', function(done) {
const cache = createCache([{
id: '/subscriptions/123/providers/Microsoft.Security/pricings/SqlServers',
name: 'SqlServers',
pricingTier: 'Standard'
}]);
const settings = {
check_level: 'subscription'
};

const cache = createCache(
null,
[]
);
plugin.run(cache, settings, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Azure Defender is enabled for SQL Servers at subscription level');
done();
});
});

auth.run(cache, {}, callback);
});
it('should give failing result if Defender is not enabled at subscription level', function(done) {
const cache = createCache([{
id: '/subscriptions/123/providers/Microsoft.Security/pricings/SqlServers',
name: 'SqlServers',
pricingTier: 'Free'
}]);
const settings = {
check_level: 'subscription'
};

it('should give failing result if Azure Defender for SQL Server Databases is not enabled', function(done) {
const callback = (err, results) => {
plugin.run(cache, settings, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Azure Defender is not enabled for SQL Server Databases');
expect(results[0].region).to.equal('global');
done()
};
expect(results[0].message).to.include('Azure Defender is not enabled for SQL Servers at subscription level');
done();
});
});

it('should give passing result if Defender is enabled at resource level', function(done) {
const cache = createCache(
null,
[
{
"id": "/subscriptions/e79d9a03-3ab3-4481-bdcd-c5db1d55420a/providers/Microsoft.Security/pricings/default",
"name": "SqlServers",
"type": "Microsoft.Security/pricings",
"pricingTier": "free",
"location": "global"
}
]
[{
id: '/subscriptions/123/providers/Microsoft.Security/pricings/SqlServers',
name: 'SqlServers',
pricingTier: 'Free'
}],
[{
id: '/subscriptions/123/servers/test-server'
}],
[{
id: '/subscriptions/123/servers/test-server/security',
state: 'Enabled'
}]
);
const settings = {
check_level: 'resource'
};

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

it('should give passing result if Azure Defender for SQL Server Databases is enabled', function(done) {
const callback = (err, results) => {
plugin.run(cache, settings, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('Azure Defender is enabled for SQL Server Databases');
expect(results[0].region).to.equal('global');
done()
};
expect(results[0].message).to.include('Azure Defender is enabled for SQL server');
done();
});
});

it('should give failing result if Defender is not enabled at resource level', function(done) {
const cache = createCache(
null,
[
{
"id": "/subscriptions/e79d9a03-3ab3-4481-bdcd-c5db1d55420a/providers/Microsoft.Security/pricings/default",
"name": "SqlServers",
"type": "Microsoft.Security/pricings",
"pricingTier": "Standard",
"location": "global"
}
]
[{
id: '/subscriptions/123/providers/Microsoft.Security/pricings/SqlServers',
name: 'SqlServers',
pricingTier: 'Free'
}],
[{
id: '/subscriptions/123/servers/test-server'
}],
[{
id: '/subscriptions/123/servers/test-server/security',
state: 'Disabled'
}]
);
const settings = {
check_level: 'resource'
};

plugin.run(cache, settings, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('Azure Defender is not enabled for SQL server');
done();
});
});

auth.run(cache, {}, callback);
})
})
});
// Add other necessary test cases for error conditions
});
});

function createCache(pricingData, serversData, securityData) {
return {
pricings: {
list: {
global: {
data: pricingData
}
}
},
servers: {
listSql: {
'eastus': {
data: serversData
}
}
},
serverSecurityAlertPolicies: {
listByServer: {
'eastus': {
'/subscriptions/123/servers/test-server': {
data: securityData
}
}
}
}
};
}
Loading