Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 17 additions & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -732,10 +732,14 @@ module.exports = {
'blobServiceEncryption' : require(__dirname + '/plugins/azure/storageaccounts/blobServiceEncryption.js'),
'trustedMsAccessEnabled' : require(__dirname + '/plugins/azure/storageaccounts/trustedMsAccessEnabled.js'),
'blobSoftDeletionEnabled' : require(__dirname + '/plugins/azure/storageaccounts/blobSoftDeletionEnabled.js'),
'containerSoftDeletionEnabled' : require(__dirname + '/plugins/azure/storageaccounts/containerSoftDeletionEnabled.js'),
'blobVersioningEnabled' : require(__dirname + '/plugins/azure/storageaccounts/blobVersioningEnabled.js'),
'storageAccountKeyRotationReminder': require(__dirname + '/plugins/azure/storageaccounts/storageAccountKeyRotationReminder.js'),
'storageAccountKeyRotation' : require(__dirname + '/plugins/azure/storageaccounts/storageAccountKeyRotation.js'),
'sharedKeyAccessDisabled' : require(__dirname + '/plugins/azure/storageaccounts/sharedKeyAccessDisabled.js'),
'storageAccountEntraIdAuthDefault': require(__dirname + '/plugins/azure/storageaccounts/storageAccountEntraIdAuthDefault.js'),
'crossTenantReplicationDisabled': require(__dirname + '/plugins/azure/storageaccounts/crossTenantReplicationDisabled.js'),
'blobAnonymousAccessDisabled' : require(__dirname + '/plugins/azure/storageaccounts/blobAnonymousAccessDisabled.js'),
'geoRedundantStorage' : require(__dirname + '/plugins/azure/storageaccounts/geoRedundantStorage.js'),
'fileShareSoftDeletionEnabled' : require(__dirname + '/plugins/azure/storageaccounts/fileShareSoftDeletionEnabled.js'),
'fileShareSmbProtocolVersion' : require(__dirname + '/plugins/azure/storageaccounts/fileShareSmbProtocolVersion.js'),
Expand Down Expand Up @@ -785,8 +789,10 @@ module.exports = {
'redisCacheVNetIntegrated' : require(__dirname + '/plugins/azure/redisCache/redisCacheVNetIntegrated.js'),

'multipleSubnets' : require(__dirname + '/plugins/azure/virtualnetworks/multipleSubnets.js'),
'subnetNetworkSecurityGroup' : require(__dirname + '/plugins/azure/virtualnetworks/subnetNetworkSecurityGroup.js'),
'ddosStandardProtectionEnabled' : require(__dirname + '/plugins/azure/virtualnetworks/ddosStandardProtectionEnabled.js'),
'noNetworkGatewaysInUse' : require(__dirname + '/plugins/azure/virtualnetworks/noNetworkGatewaysInUse.js'),
'vpnGatewayEntraIdAuth' : require(__dirname + '/plugins/azure/virtualnetworks/vpnGatewayEntraIdAuth.js'),
'virtualNetworkPeering' : require(__dirname + '/plugins/azure/virtualnetworks/virtualNetworkPeering.js'),
'noGatewayConnections' : require(__dirname + '/plugins/azure/virtualnetworks/noGatewayConnections.js'),
'managedNatGateway' : require(__dirname + '/plugins/azure/virtualnetworks/managedNatGateway.js'),
Expand Down Expand Up @@ -849,6 +855,7 @@ module.exports = {
'bastionHostHasTags' : require(__dirname + '/plugins/azure/bastion/bastionHostHasTags.js'),

'logProfileArchiveData' : require(__dirname + '/plugins/azure/monitor/logProfileArchiveData.js'),
'appInsightsConfigured' : require(__dirname + '/plugins/azure/monitor/appInsightsConfigured.js'),
'logAnalyticsWorkspacePublic' : require(__dirname + '/plugins/azure/monitor/logAnalyticsWorkspacePublic.js'),
'monitorLogsEnabled' : require(__dirname + '/plugins/azure/monitor/monitorLogsEnabled.js'),
'diagnosticsCapturedCategories' : require(__dirname + '/plugins/azure/monitor/diagnosticsCapturedCategories.js'),
Expand All @@ -857,6 +864,7 @@ module.exports = {

'securityPolicyAlertsEnabled' : require(__dirname + '/plugins/azure/logalerts/securityPolicyAlertsEnabled.js'),
'nsgLoggingEnabled' : require(__dirname + '/plugins/azure/logalerts/nsgLoggingEnabled.js'),
'serviceHealthAlertEnabled' : require(__dirname + '/plugins/azure/logalerts/serviceHealthAlertEnabled.js'),
'sqlServerFirewallRuleEnabled' : require(__dirname + '/plugins/azure/logalerts/sqlServerFirewallRuleEnabled.js'),
'virtualNetworkRuleEnabled' : require(__dirname + '/plugins/azure/logalerts/virtualNetworkRuleEnabled.js'),
'securitySolutionLogging' : require(__dirname + '/plugins/azure/logalerts/securitySolutionLogging.js'),
Expand Down Expand Up @@ -1065,7 +1073,10 @@ module.exports = {
'passwordRequiresUppercase' : require(__dirname + '/plugins/azure/entraid/passwordRequiresUppercase.js'),
'minPasswordLength' : require(__dirname + '/plugins/azure/entraid/minPasswordLength.js'),
'ensureNoGuestUser' : require(__dirname + '/plugins/azure/entraid/ensureNoGuestUser.js'),
'securityDefaultsEnabled' : require(__dirname + '/plugins/azure/entraid/securityDefaultsEnabled.js'),
'userAccessAdminRestricted' : require(__dirname + '/plugins/azure/entraid/userAccessAdminRestricted.js'),
'disabledUserRoleAssignments' : require(__dirname + '/plugins/azure/entraid/disabledUserRoleAssignments.js'),
'resourceLockAdminRole' : require(__dirname + '/plugins/azure/entraid/resourceLockAdminRole.js'),
'subscriptionOwnerCount' : require(__dirname + '/plugins/azure/entraid/subscriptionOwnerCount.js'),
'noCustomOwnerRoles' : require(__dirname + '/plugins/azure/entraid/noCustomOwnerRoles.js'),
'appOrgnaizationalDirectoryAccess' : require(__dirname + '/plugins/azure/entraid/appOrgnaizationalDirectoryAccess.js'),
Expand Down Expand Up @@ -1099,6 +1110,9 @@ module.exports = {
'keyVaultSecretExpiry' : require(__dirname + '/plugins/azure/keyvaults/keyVaultSecretExpiry.js'),
'keyVaultSecretExpiryNonRbac' : require(__dirname + '/plugins/azure/keyvaults/keyVaultSecretExpiryNonRbac.js'),
'keyVaultKeyExpiry' : require(__dirname + '/plugins/azure/keyvaults/keyVaultKeyExpiry.js'),
'keyVaultRbacEnabled' : require(__dirname + '/plugins/azure/keyvaults/keyVaultRbacEnabled.js'),
'keyVaultKeyRotation' : require(__dirname + '/plugins/azure/keyvaults/keyVaultKeyRotation.js'),
'certificateValidityPeriod' : require(__dirname + '/plugins/azure/keyvaults/certificateValidityPeriod.js'),
'keyVaultKeyExpiryNonRbac' : require(__dirname + '/plugins/azure/keyvaults/keyVaultKeyExpiryNonRbac.js'),
'allowedCertificateKeyTypes' : require(__dirname + '/plugins/azure/keyvaults/allowedCertificateKeyTypes.js'),
'appTierCmkInUse' : require(__dirname + '/plugins/azure/keyvaults/appTierCmkInUse.js'),
Expand Down Expand Up @@ -1135,6 +1149,7 @@ module.exports = {
'enableDefenderForCosmosDB' : require(__dirname + '/plugins/azure/defender/enableDefenderForCosmosDB.js'),
'enableDefenderForSqlServersVMs': require(__dirname + '/plugins/azure/defender/enableDefenderForSqlServersVMs.js'),
'highSeverityAlertsEnabled' : require(__dirname + '/plugins/azure/defender/highSeverityAlertsEnabled.js'),
'attackPathNotificationsEnabled': require(__dirname + '/plugins/azure/defender/attackPathNotificationsEnabled.js'),
'standardPricingEnabled' : require(__dirname + '/plugins/azure/defender/standardPricingEnabled.js'),
'monitorExternalAccounts' : require(__dirname + '/plugins/azure/defender/monitorExternalAccounts.js'),
'monitorIpForwarding' : require(__dirname + '/plugins/azure/defender/monitorIpForwarding.js'),
Expand All @@ -1151,6 +1166,7 @@ module.exports = {
'securityContactsEnabled' : require(__dirname + '/plugins/azure/defender/securityContactsEnabled.js'),

'agWafEnabled' : require(__dirname + '/plugins/azure/applicationGateway/agWafEnabled'),
'agHttp2Enabled' : require(__dirname + '/plugins/azure/applicationGateway/agHttp2Enabled'),
'applicationGatewayHasTags' : require(__dirname + '/plugins/azure/applicationGateway/applicationGatewayHasTags.js'),
'agSecurityLoggingEnabled' : require(__dirname + '/plugins/azure/applicationGateway/agSecurityLoggingEnabled.js'),
'agSslPolicy' : require(__dirname + '/plugins/azure/applicationGateway/agSslPolicy'),
Expand All @@ -1165,6 +1181,7 @@ module.exports = {
'rgHasTags' : require(__dirname + '/plugins/azure/resourceGroup/rgHasTags.js'),

'wafPolicyHasTags' : require(__dirname + '/plugins/azure/waf/wafPolicyHasTags.js'),
'wafPolicyBotProtection' : require(__dirname + '/plugins/azure/waf/wafPolicyBotProtection.js'),

'recoveryVaultByokEncrypted' : require(__dirname + '/plugins/azure/recoveryService/recoveryVaultByokEncrypted.js'),
'recoveryVaultLoggingEnabled' : require(__dirname + '/plugins/azure/recoveryService/recoveryVaultLoggingEnabled.js'),
Expand Down
52 changes: 52 additions & 0 deletions plugins/azure/applicationGateway/agHttp2Enabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const async = require('async');
const helpers = require('../../../helpers/azure');

module.exports = {
title: 'Application Gateway HTTP2 Enabled',
category: 'Application Gateway',
domain: 'Network Access Control',
severity: 'Low',
description: 'Ensures that HTTP2 is enabled for Application Gateways.',
more_info: 'HTTP2 support is available to clients that connect to application gateway listeners and provides improved performance and efficiency over HTTP1.1. Clients and backend services that do not support HTTP2 fall back to HTTP1.1.',
recommended_action: 'Enable HTTP2 from the configuration settings of the application gateway.',
link: 'https://learn.microsoft.com/en-us/azure/application-gateway/configuration-overview',
apis: ['applicationGateway:listAll'],
realtime_triggers: ['microsoftnetwork:applicationgateways:write', 'microsoftnetwork:applicationgateways:delete'],

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

async.each(locations.applicationGateway, (location, rcb) => {
var appGateways = helpers.addSource(cache, source,
['applicationGateway', 'listAll', location]);

if (!appGateways) return rcb();

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

if (!appGateways.data.length) {
helpers.addResult(results, 0, 'No existing Application Gateway found', location);
return rcb();
}

for (let appGateway of appGateways.data) {
if (!appGateway.id) continue;

if (appGateway.enableHttp2) {
helpers.addResult(results, 0, 'HTTP2 is enabled for Application Gateway', location, appGateway.id);
} else {
helpers.addResult(results, 2, 'HTTP2 is not enabled for Application Gateway', location, appGateway.id);
}
}

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

const appGateways = [
{
'name': 'test-ag',
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Network/applicationGateways/test-ag',
'type': 'Microsoft.Network/applicationGateways',
'location': 'eastus',
'enableHttp2': true
},
{
'name': 'test-ag',
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Network/applicationGateways/test-ag',
'type': 'Microsoft.Network/applicationGateways',
'location': 'eastus',
'enableHttp2': false
},
{
'name': 'test-ag',
'id': '/subscriptions/123/resourceGroups/aqua-resource-group/providers/Microsoft.Network/applicationGateways/test-ag',
'type': 'Microsoft.Network/applicationGateways',
'location': 'eastus'
}
];

const createCache = (appGateways) => {
return {
applicationGateway: {
listAll: {
'eastus': {
data: appGateways
}
}
}
};
};

const createErrorCache = () => {
return {
applicationGateway: {
listAll: {
'eastus': {}
}
}
};
};

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

it('should give unknown result if unable to query for application gateways', function (done) {
const cache = createErrorCache();
agHttp2Enabled.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 Application Gateway');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give passing result if HTTP2 is enabled for application gateway', function (done) {
const cache = createCache([appGateways[0]]);
agHttp2Enabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(0);
expect(results[0].message).to.include('HTTP2 is enabled for Application Gateway');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if HTTP2 is not enabled for application gateway', function (done) {
const cache = createCache([appGateways[1]]);
agHttp2Enabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('HTTP2 is not enabled for Application Gateway');
expect(results[0].region).to.equal('eastus');
done();
});
});

it('should give failing result if HTTP2 setting does not exist for application gateway', function (done) {
const cache = createCache([appGateways[2]]);
agHttp2Enabled.run(cache, {}, (err, results) => {
expect(results.length).to.equal(1);
expect(results[0].status).to.equal(2);
expect(results[0].message).to.include('HTTP2 is not enabled for Application Gateway');
expect(results[0].region).to.equal('eastus');
done();
});
});
});
});
58 changes: 58 additions & 0 deletions plugins/azure/defender/attackPathNotificationsEnabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const async = require('async');
const helpers = require('../../../helpers/azure');

module.exports = {
title: 'Attack Path Notifications Enabled',
category: 'Defender',
domain: 'Management and Governance',
severity: 'Low',
description: 'Ensures that email notifications for attack paths are enabled for the subscription.',
more_info: 'Enabling attack path email notifications ensures that the subscription owner or other designated security contact is notified of new attack paths detected by Microsoft Defender for Cloud, allowing for quick mitigation of the associated risks.',
recommended_action: 'Enable email notifications for attack paths from the Microsoft Defender for Cloud email notifications settings.',
link: 'https://learn.microsoft.com/en-us/azure/defender-for-cloud/configure-email-notifications',
apis: ['securityContactv3:listAll'],
realtime_triggers: ['microsoftsecurity:securitycontacts:write', 'microsoftsecurity:securitycontacts:delete'],

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

async.each(locations.securityContactv3, (location, rcb) => {
var securityContacts = helpers.addSource(cache, source,
['securityContactv3', 'listAll', location]);

if (!securityContacts) return rcb();

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

if (!securityContacts.data.length) {
helpers.addResult(results, 2, 'No existing security contacts found', location);
return rcb();
}

for (let contact of securityContacts.data) {
if (!contact.id) continue;

var attackPathSource = contact.notificationsSources ?
contact.notificationsSources.find(notifSource => notifSource.sourceType &&
notifSource.sourceType.toLowerCase() === 'attackpath') : null;

if (attackPathSource && attackPathSource.minimalRiskLevel) {
helpers.addResult(results, 0,
`Attack path email notifications are enabled with minimum risk level ${attackPathSource.minimalRiskLevel}`, location, contact.id);
} else {
helpers.addResult(results, 2, 'Attack path email notifications are not enabled', location, contact.id);
}
}

rcb();
}, function() {
callback(null, results, source);
});
}
};
Loading
Loading