From 2ce88af34a5b74e1f036a16eeed259e02ccbacd7 Mon Sep 17 00:00:00 2001 From: Meerab_shafique Date: Sun, 9 Jun 2024 20:28:29 +0500 Subject: [PATCH 01/73] M/Azure/Api-Management-Service-Managed-Identity --- exports.js | 2 + helpers/azure/api.js | 5 + helpers/azure/locations.js | 3 +- helpers/azure/locations_gov.js | 3 +- helpers/azure/resources.js | 3 + .../apiInstanceManagedIdentity.js | 52 +++++++++ .../apiInstanceManagedIdentity.spec.js | 101 ++++++++++++++++++ 7 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 plugins/azure/apiManagement/apiInstanceManagedIdentity.js create mode 100644 plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..4f35967565 100644 --- a/exports.js +++ b/exports.js @@ -1195,6 +1195,8 @@ module.exports = { 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), + 'apiInstanceManagedIdentity' : require(__dirname + '/plugins/azure/apiManagement/apiInstanceManagedIdentity.js'), + }, github: { 'publicKeysRotated' : require(__dirname + '/plugins/github/users/publicKeysRotated.js'), diff --git a/helpers/azure/api.js b/helpers/azure/api.js index 150b7491a2..f25333fd6c 100644 --- a/helpers/azure/api.js +++ b/helpers/azure/api.js @@ -530,6 +530,11 @@ var calls = { url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Databricks/workspaces?api-version=2023-02-01' } }, + apiManagementService: { + list: { + url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/service?api-version=2022-08-01' + } + }, // For CIEM aad: { listRoleAssignments: { diff --git a/helpers/azure/locations.js b/helpers/azure/locations.js index 280fb294ea..8b71ca8cbd 100644 --- a/helpers/azure/locations.js +++ b/helpers/azure/locations.js @@ -134,5 +134,6 @@ module.exports = { databricks: locations, containerApps: locations, batchAccounts: locations, - machineLearning: locations + machineLearning: locations, + apiManagementService: locations }; diff --git a/helpers/azure/locations_gov.js b/helpers/azure/locations_gov.js index 2e55d01403..cd3c7dcb13 100644 --- a/helpers/azure/locations_gov.js +++ b/helpers/azure/locations_gov.js @@ -84,5 +84,6 @@ module.exports = { publicIpAddresses: locations, computeGalleries: locations, databricks: locations, - containerApps: locations + containerApps: locations, + apiManagementService: locations }; diff --git a/helpers/azure/resources.js b/helpers/azure/resources.js index 111bd05ee4..7c05970efa 100644 --- a/helpers/azure/resources.js +++ b/helpers/azure/resources.js @@ -306,5 +306,8 @@ module.exports = { }, machineLearning: { listWorkspaces: 'id' + }, + apiManagementService: { + list: 'id' } }; diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js new file mode 100644 index 0000000000..256f0487e8 --- /dev/null +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js @@ -0,0 +1,52 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'API Management Instance Managed Identity', + category: 'API Management', + domain: 'Developer Tools', + severity: 'Medium', + description: 'Ensures that Azure API Management service instance has managed identity enabled.', + more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', + link: 'https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity', + recommended_action: 'Modify API Management instance and add managed identity.', + apis: ['apiManagementService:list'], + realtime_triggers: ['microsoftapimanagement:service:write','microsoftapimanagement:service:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.apiManagementService, function(location, rcb){ + var apiManagementService = helpers.addSource(cache, source, + ['apiManagementService', 'list', location]); + + if (!apiManagementService) return rcb(); + + if (apiManagementService.err || !apiManagementService.data) { + helpers.addResult(results, 3, 'Unable to query API Management service instances:' + helpers.addError(apiManagementService), location); + return rcb(); + } + + if (!apiManagementService.data.length) { + helpers.addResult(results, 0, 'No existing API Management service instances found', location); + return rcb(); + } + + for (let apiInstance of apiManagementService.data) { + if (!apiInstance.id) continue; + + if (apiInstance.identity) { + helpers.addResult(results, 0, 'API Management service instance has managed identity enabled', location, apiInstance.id); + } else { + helpers.addResult(results, 2, 'API Management service instance does not have managed identity enabled', location, apiInstance.id); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js new file mode 100644 index 0000000000..3416bf65e7 --- /dev/null +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js @@ -0,0 +1,101 @@ +var expect = require('chai').expect; +var apiInstanceManagedIdentity = require('./apiInstanceManagedIdentity.js'); + +const apiManagementService = [ + { + "etag": "AAAAAAGIUI4=", + "publisherEmail": "dummy.@aquasec.com", + "publisherName": "dummy", + "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com", + "provisioningState": "Succeeded", + "targetProvisioningState": "", + "identity": null, + "zones": null, + "location": "East US", + "tags": {}, + "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "name": "meerab", + "type": "Microsoft.ApiManagement/service" + }, + { + "etag": "AAAAAAGIUI4=", + "publisherEmail": "dummy.@aquasec.com", + "publisherName": "dummy", + "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com", + "provisioningState": "Succeeded", + "targetProvisioningState": "", + "identity": { + "type": "SystemAssigned", + "principalId": "fdd1f197-d0e0-4d04-a5ef-9dbb654afd14", + "tenantId": "d207c7bd-fcb1-4dd3-855a-cfd2f9b651e8" + }, + "zones": null, + "location": "East US", + "tags": {}, + "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "name": "meerab", + "type": "Microsoft.ApiManagement/service" + } +]; + +const createCache = (apiManagementService, err) => { + return { + apiManagementService: { + list: { + 'eastus': { + data: apiManagementService, + err: err + } + } + } + } +}; + +describe('apiInstanceManagedIdentity', function () { + describe('run', function () { + + it('should give pass result if No existing API Management service instances found', function (done) { + const cache = createCache([]); + apiInstanceManagedIdentity.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 API Management service instances found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if Unable to query API Management service instances:', function (done) { + const cache = createCache(null, 'Error'); + apiInstanceManagedIdentity.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 API Management service instances:'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if API Management service instances has managed identity enabled', function (done) { + const cache = createCache([apiManagementService[1]]); + apiInstanceManagedIdentity.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('API Management service instance has managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if API Management service instances does not have managed identity enabled', function (done) { + const cache = createCache([apiManagementService[0]]); + apiInstanceManagedIdentity.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('API Management service instance does not have managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From 6f1531c6919f9118744249d1396daffc8195b144 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 9 Jun 2024 21:09:47 +0500 Subject: [PATCH 02/73] M/Azure/Api-Management-Service-Has-Tags --- exports.js | 1 + .../azure/apiManagement/apiInstanceHasTags.js | 52 +++++++++ .../apiManagement/apiInstanceHasTags.spec.js | 101 ++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 plugins/azure/apiManagement/apiInstanceHasTags.js create mode 100644 plugins/azure/apiManagement/apiInstanceHasTags.spec.js diff --git a/exports.js b/exports.js index 4f35967565..031fad506e 100644 --- a/exports.js +++ b/exports.js @@ -1196,6 +1196,7 @@ module.exports = { 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), 'apiInstanceManagedIdentity' : require(__dirname + '/plugins/azure/apiManagement/apiInstanceManagedIdentity.js'), + 'apiInstanceHasTags' : require(__dirname + '/plugins/azure/apiManagement/apiInstanceHasTags.js'), }, github: { diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.js b/plugins/azure/apiManagement/apiInstanceHasTags.js new file mode 100644 index 0000000000..642f059719 --- /dev/null +++ b/plugins/azure/apiManagement/apiInstanceHasTags.js @@ -0,0 +1,52 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'API Management Instance Has Tags', + category: 'API Management', + domain: 'Developer Tools', + severity: 'Medium', + description: 'Ensures that Azure API Management service instance has tags associated.', + more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', + link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources', + recommended_action: 'Modify API Management instance and add tags.', + apis: ['apiManagementService:list'], + realtime_triggers: ['microsoftapimanagement:service:write','microsoftapimanagement:service:delete','microsoftresources:tags:write'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.apiManagementService, function(location, rcb){ + var apiManagementService = helpers.addSource(cache, source, + ['apiManagementService', 'list', location]); + + if (!apiManagementService) return rcb(); + + if (apiManagementService.err || !apiManagementService.data) { + helpers.addResult(results, 3, 'Unable to query API Management service instances:' + helpers.addError(apiManagementService), location); + return rcb(); + } + + if (!apiManagementService.data.length) { + helpers.addResult(results, 0, 'No existing API Management service instances found', location); + return rcb(); + } + + for (let apiInstance of apiManagementService.data) { + if (!apiInstance.id) continue; + + if (apiInstance.tags && Object.entries(apiInstance.tags).length > 0) { + helpers.addResult(results, 0, 'API Management service instance has tags associated', location, apiInstance.id); + } else { + helpers.addResult(results, 2, 'API Management service instance does not have tags associated', location, apiInstance.id); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.spec.js b/plugins/azure/apiManagement/apiInstanceHasTags.spec.js new file mode 100644 index 0000000000..260c2720a5 --- /dev/null +++ b/plugins/azure/apiManagement/apiInstanceHasTags.spec.js @@ -0,0 +1,101 @@ +var expect = require('chai').expect; +var apiInstanceHasTags = require('./apiInstanceHasTags.js'); + +const apiManagementService = [ + { + "etag": "AAAAAAGIUI4=", + "publisherEmail": "dummy.@aquasec.com", + "publisherName": "dummy", + "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com", + "provisioningState": "Succeeded", + "targetProvisioningState": "", + "identity": null, + "zones": null, + "tags": {}, + "location": "East US", + "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "name": "meerab", + "type": "Microsoft.ApiManagement/service" + }, + { + "etag": "AAAAAAGIUI4=", + "publisherEmail": "dummy.@aquasec.com", + "publisherName": "dummy", + "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com", + "provisioningState": "Succeeded", + "targetProvisioningState": "", + "identity": { + "type": "SystemAssigned", + "principalId": "fdd1f197-d0e0-4d04-a5ef-9dbb654afd14", + "tenantId": "d207c7bd-fcb1-4dd3-855a-cfd2f9b651e8" + }, + "zones": null, + "location": "East US", + "tags": {"key": "value"}, + "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "name": "meerab", + "type": "Microsoft.ApiManagement/service" + } +]; + +const createCache = (apiManagementService, err) => { + return { + apiManagementService: { + list: { + 'eastus': { + data: apiManagementService, + err: err + } + } + } + } +}; + +describe('apiInstanceHasTags', function () { + describe('run', function () { + + it('should give pass result if No existing API Management service instances found', function (done) { + const cache = createCache([]); + apiInstanceHasTags.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 API Management service instances found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if Unable to query API Management service instances', function (done) { + const cache = createCache(null, 'Error'); + apiInstanceHasTags.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 API Management service instances'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if API Management service instances has tags associated', function (done) { + const cache = createCache([apiManagementService[1]]); + apiInstanceHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('API Management service instance has tags associated'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if API Management service instances does not have tags associated', function (done) { + const cache = createCache([apiManagementService[0]]); + apiInstanceHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('API Management service instance does not have tags associated'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From ce7761339cbfd8f7e756d29a1e8af8b926e50e32 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 10 Jun 2024 01:40:32 +0500 Subject: [PATCH 03/73] M/Aws/CodeBuild-Project-Env-Privileged-Mode --- exports.js | 1 + .../buildProjectEnvPriviligedMode.js | 72 +++++++++ .../buildProjectEnvPriviligedMode.spec.js | 145 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 plugins/aws/codebuild/buildProjectEnvPriviligedMode.js create mode 100644 plugins/aws/codebuild/buildProjectEnvPriviligedMode.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..0a22975e57 100644 --- a/exports.js +++ b/exports.js @@ -608,6 +608,7 @@ module.exports = { 'codebuildValidSourceProviders' : require(__dirname + '/plugins/aws/codebuild/codebuildValidSourceProviders.js'), 'projectArtifactsEncrypted' : require(__dirname + '/plugins/aws/codebuild/projectArtifactsEncrypted.js'), + 'buildProjectEnvPriviligedMode' : require(__dirname + '/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js'), 'codestarValidRepoProviders' : require(__dirname + '/plugins/aws/codestar/codestarValidRepoProviders.js'), 'codestarHasTags' : require(__dirname + '/plugins/aws/codestar/codestarHasTags.js'), diff --git a/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js new file mode 100644 index 0000000000..df6c538a82 --- /dev/null +++ b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js @@ -0,0 +1,72 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'Build Project Environment Privileged Mode', + category: 'CodeBuild', + domain: 'Application Integration', + severity: 'Medium', + description: 'Ensure that your AWS CodeBuild build project environment has privileged mode disabled.', + more_info: 'Enabling privileged mode for CodeBuild project environments allows the build container to have elevated permissions on the host machine, which can potentially lead to security vulnerabilities and unauthorized access.', + recommended_action: 'Modify CodeBuild build project and disable environment privileged mode.', + link: 'https://docs.aws.amazon.com/codebuild/latest/userguide/change-project-console.html', + apis: ['CodeBuild:listProjects', 'CodeBuild:batchGetProjects','STS:GetCallerIdentity'], + realtime_triggers: ['codebuild:CreateProject', 'codebuild:UpdateProject','codebuild:DeleteProject'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + var acctRegion = helpers.defaultRegion(settings); + var awsOrGov = helpers.defaultPartition(settings); + var accountId = helpers.addSource(cache, source, ['STS', 'GetCallerIdentity', acctRegion, 'data']); + + async.each(regions.codebuild, function(region, rcb){ + var listProjects = helpers.addSource(cache, source, + ['codebuild', 'listProjects', region]); + + if (!listProjects) return rcb(); + + if (listProjects.err || !listProjects.data) { + helpers.addResult(results, 3, + `Unable to list CodeBuild projects: ${helpers.addError(listProjects)}`, region); + return rcb(); + } + + if (!listProjects.data.length) { + helpers.addResult(results, 0, + 'No CodeBuild projects found', region); + return rcb(); + } + + for (let project of listProjects.data) { + var resource = `arn:${awsOrGov}:codebuild:${region}:${accountId}:project/${project}`; + + let batchGetProjects = helpers.addSource(cache, source, + ['codebuild', 'batchGetProjects', region, project]); + + if (!batchGetProjects || batchGetProjects.err || !batchGetProjects.data || + !batchGetProjects.data.projects || !batchGetProjects.data.projects.length) { + helpers.addResult(results, 3, + `Unable to query CodeBuild project: ${helpers.addError(batchGetProjects)}`, region, resource); + } else { + if(batchGetProjects.data.projects[0] && + batchGetProjects.data.projects[0].environment && + batchGetProjects.data.projects[0].environment.privilegedMode) { + helpers.addResult(results, 2, + 'CodeBuild project environment has privileged mode enabled', region, resource); + } else { + helpers.addResult(results, 0, + 'CodeBuild project environment has privileged mode disabled', region, resource); + } + } + + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/aws/codebuild/buildProjectEnvPriviligedMode.spec.js b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.spec.js new file mode 100644 index 0000000000..652a67efe3 --- /dev/null +++ b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.spec.js @@ -0,0 +1,145 @@ +var expect = require('chai').expect; +const buildProjectEnvPriviligedMode = require('./buildProjectEnvPriviligedMode'); + +const listProjects = [ + 'test-project' +]; + + +const batchGetProjects = [ + { + "projects": [ + { + "name": "test-project", + "arn": "arn:aws:codebuild:us-east-1:111122223333:project/test-project", + "environment": { + "type": "ARM_CONTAINER", + "image": "aws/codebuild/amazonlinux2-aarch64-standard:2.0", + "computeType": "BUILD_GENERAL1_SMALL", + "environmentVariables": [], + "privilegedMode": true, + "imagePullCredentialsType": "CODEBUILD" + }, + } + ], + }, + { + "projects": [ + { + "name": "test-project", + "arn": "arn:aws:codebuild:us-east-1:111122223333:project/test-project", + "environment": { + "type": "ARM_CONTAINER", + "image": "aws/codebuild/amazonlinux2-aarch64-standard:2.0", + "computeType": "BUILD_GENERAL1_SMALL", + "environmentVariables": [], + "privilegedMode": false, + "imagePullCredentialsType": "CODEBUILD" + }, + } + ], + } +] + +const createCache = (listProjects, batchGetProjects, listProjectsErr, batchGetProjectsErr) => { + let project = (listProjects && listProjects.length) ? listProjects[0] : null; + return { + codebuild: { + listProjects: { + 'us-east-1': { + data: listProjects, + err: listProjectsErr + } + }, + batchGetProjects: { + 'us-east-1': { + [project]: { + data: batchGetProjects, + err: batchGetProjectsErr + } + } + } + } + } +}; + +const createNullCache = () => { + return { + codebuild: { + listProjects: { + 'us-east-1': { 'err': 'Error listing batchProjects' }, + }, + }, + }; +}; + +describe('buildProjectEnvPriviligedMode', function () { + describe('run', function () { + + it('should PASS if no CodeBuild projects found', function (done) { + const cache = createCache([]); + buildProjectEnvPriviligedMode.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('No CodeBuild projects found'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to list codebuild project', function (done) { + const cache = createNullCache(); + buildProjectEnvPriviligedMode.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 list CodeBuild projects:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to get CodeBuild project', function (done) { + const cache = createCache(listProjects, null, null, { message: 'Unable to query CodeBuild project' }); + buildProjectEnvPriviligedMode.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 CodeBuild project:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to get CodeBuild project', function (done) { + const cache = createCache(listProjects, null, null, { message: 'Unable to query CodeBuild project' }); + buildProjectEnvPriviligedMode.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 CodeBuild project:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should FAIL if CodeBuild project environment has privileged mode enabled', function (done) { + const cache = createCache(listProjects, batchGetProjects[0], null, null); + buildProjectEnvPriviligedMode.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('CodeBuild project environment has privileged mode enabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should PASS if CodeBuild project environment has privileged mode disabled', function (done) { + const cache = createCache(listProjects, batchGetProjects[1], null, null); + buildProjectEnvPriviligedMode.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('CodeBuild project environment has privileged mode disabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + }); +}); From d34bc3d6aa69987592031ae871c7345a3aded84a Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 10 Jun 2024 02:17:43 +0500 Subject: [PATCH 04/73] M/Aws/CodeBuild-Project-Logging-Enabled --- exports.js | 1 + .../codeBuildProjectLoggingEnabled.spec.js | 163 ++++++++++++++++++ .../codebuildProjectLoggingEnabled.js | 75 ++++++++ 3 files changed, 239 insertions(+) create mode 100644 plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js create mode 100644 plugins/aws/codebuild/codebuildProjectLoggingEnabled.js diff --git a/exports.js b/exports.js index 9ca097916d..4611d84b16 100644 --- a/exports.js +++ b/exports.js @@ -608,6 +608,7 @@ module.exports = { 'codebuildValidSourceProviders' : require(__dirname + '/plugins/aws/codebuild/codebuildValidSourceProviders.js'), 'projectArtifactsEncrypted' : require(__dirname + '/plugins/aws/codebuild/projectArtifactsEncrypted.js'), + 'codebuildProjectLoggingEnabled': require(__dirname + '/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js'), 'codestarValidRepoProviders' : require(__dirname + '/plugins/aws/codestar/codestarValidRepoProviders.js'), 'codestarHasTags' : require(__dirname + '/plugins/aws/codestar/codestarHasTags.js'), diff --git a/plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js b/plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js new file mode 100644 index 0000000000..8a4f592701 --- /dev/null +++ b/plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js @@ -0,0 +1,163 @@ +var expect = require('chai').expect; +const codebuildProjectLoggingEnabled = require('./codebuildProjectLoggingEnabled'); + +const listProjects = [ + 'test-project' +]; + + +const batchGetProjects = [ + { + "projects": [ + { + "name": "test-project", + "arn": "arn:aws:codebuild:us-east-1:111122223333:project/test-project", + "environment": { + "type": "ARM_CONTAINER", + "image": "aws/codebuild/amazonlinux2-aarch64-standard:2.0", + "computeType": "BUILD_GENERAL1_SMALL", + "environmentVariables": [], + "privilegedMode": true, + "imagePullCredentialsType": "CODEBUILD" + }, + "logsConfig": { + "cloudWatchLogs": { + "status": "DISABLED", + }, + "s3Logs": { + "status": "DISABLED", + "encryptionDisabled": false, + }, + } + } + ], + }, + { + "projects": [ + { + "name": "test-project", + "arn": "arn:aws:codebuild:us-east-1:111122223333:project/test-project", + "environment": { + "type": "ARM_CONTAINER", + "image": "aws/codebuild/amazonlinux2-aarch64-standard:2.0", + "computeType": "BUILD_GENERAL1_SMALL", + "environmentVariables": [], + "privilegedMode": false, + "imagePullCredentialsType": "CODEBUILD" + }, + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + }, + "s3Logs": { + "status": "DISABLED", + "encryptionDisabled": false, + }, + } + } + ], + } +] + +const createCache = (listProjects, batchGetProjects, listProjectsErr, batchGetProjectsErr) => { + let project = (listProjects && listProjects.length) ? listProjects[0] : null; + return { + codebuild: { + listProjects: { + 'us-east-1': { + data: listProjects, + err: listProjectsErr + } + }, + batchGetProjects: { + 'us-east-1': { + [project]: { + data: batchGetProjects, + err: batchGetProjectsErr + } + } + } + } + } +}; + +const createNullCache = () => { + return { + codebuild: { + listProjects: { + 'us-east-1': { 'err': 'Error listing batchProjects' }, + }, + }, + }; +}; + +describe('codebuildProjectLoggingEnabled', function () { + describe('run', function () { + + it('should PASS if no CodeBuild projects found', function (done) { + const cache = createCache([]); + codebuildProjectLoggingEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('No CodeBuild projects found'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to list codebuild project', function (done) { + const cache = createNullCache(); + codebuildProjectLoggingEnabled.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 list CodeBuild projects:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to get CodeBuild project', function (done) { + const cache = createCache(listProjects, null, null, { message: 'Unable to query CodeBuild project' }); + codebuildProjectLoggingEnabled.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 CodeBuild project:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to get CodeBuild project', function (done) { + const cache = createCache(listProjects, null, null, { message: 'Unable to query CodeBuild project' }); + codebuildProjectLoggingEnabled.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 CodeBuild project:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should FAIL if CodeBuild project does not have logging enabled', function (done) { + const cache = createCache(listProjects, batchGetProjects[0], null, null); + codebuildProjectLoggingEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('CodeBuild project does not have logging enabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should PASS if CodeBuild project has logging enabled', function (done) { + const cache = createCache(listProjects, batchGetProjects[1], null, null); + codebuildProjectLoggingEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('CodeBuild project has logging enabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js b/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js new file mode 100644 index 0000000000..3304633934 --- /dev/null +++ b/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js @@ -0,0 +1,75 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'CodeBuild Project Logging Enabled', + category: 'CodeBuild', + domain: 'Application Integration', + severity: 'Medium', + description: 'Ensure that your AWS CodeBuild build project has S3 or Cloudwatch logs enabled.', + more_info: 'Monitoring AWS CodeBuild projects helps maintaining the reliability, availability, and performance of the resource. It helps to easily debug multi-point failure and potential incidents.', + recommended_action: 'Modify CodeBuild build project enable logging.', + link: 'https://docs.aws.amazon.com/codebuild/latest/userguide/monitoring-builds.html', + apis: ['CodeBuild:listProjects', 'CodeBuild:batchGetProjects', 'STS:GetCallerIdentity'], + realtime_triggers: ['codebuild:CreateProject', 'codebuild:UpdateProject', 'codebuild:DeleteProject'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + var acctRegion = helpers.defaultRegion(settings); + var awsOrGov = helpers.defaultPartition(settings); + var accountId = helpers.addSource(cache, source, ['STS', 'GetCallerIdentity', acctRegion, 'data']); + + async.each(regions.codebuild, function(region, rcb) { + var listProjects =helpers.addSource(cache, source, + ['codebuild', 'listProjects', region]); + + if (!listProjects) return rcb(); + + if (listProjects.err || !listProjects.data) { + helpers.addResult(results, 3, + `Unable to list CodeBuild projects: ${helpers.addError(listProjects)}`, region); + return rcb(); + } + + if (!listProjects.data.length) { + helpers.addResult(results, 0, + 'No CodeBuild projects found', region); + return rcb(); + } + + for (let project of listProjects.data) { + var resource = `arn:${awsOrGov}:codebuild:${region}:${accountId}:project/${project}`; + + let batchGetProjects = helpers.addSource(cache, source, + ['codebuild', 'batchGetProjects', region, project]); + + if (!batchGetProjects || batchGetProjects.err || !batchGetProjects.data || + !batchGetProjects.data.projects || !batchGetProjects.data.projects.length) { + helpers.addResult(results, 3, + `Unable to query CodeBuild project: ${helpers.addError(batchGetProjects)}`, region, resource); + } else { + + var found = (batchGetProjects.data.projects[0] && + batchGetProjects.data.projects[0].logsConfig && + Object.values(batchGetProjects.data.projects[0].logsConfig).some(log => log.status === 'ENABLED')) || false; + + if (found) { + helpers.addResult(results, 0, + 'CodeBuild project has logging enabled', region, resource); + } else { + helpers.addResult(results, 2, + 'CodeBuild project does not have logging enabled', region, resource); + } + } + + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; \ No newline at end of file From 74bf147c415d91289cb88b62e661a6e057b9f4a0 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 10 Jun 2024 02:18:43 +0500 Subject: [PATCH 05/73] linting --- plugins/aws/codebuild/buildProjectEnvPriviligedMode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js index df6c538a82..4ea182abcf 100644 --- a/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js +++ b/plugins/aws/codebuild/buildProjectEnvPriviligedMode.js @@ -51,11 +51,11 @@ module.exports = { helpers.addResult(results, 3, `Unable to query CodeBuild project: ${helpers.addError(batchGetProjects)}`, region, resource); } else { - if(batchGetProjects.data.projects[0] && + if (batchGetProjects.data.projects[0] && batchGetProjects.data.projects[0].environment && batchGetProjects.data.projects[0].environment.privilegedMode) { helpers.addResult(results, 2, - 'CodeBuild project environment has privileged mode enabled', region, resource); + 'CodeBuild project environment has privileged mode enabled', region, resource); } else { helpers.addResult(results, 0, 'CodeBuild project environment has privileged mode disabled', region, resource); From baf11c6b545e5eef8608c42db7e69d9a6034f01c Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 10 Jun 2024 02:19:25 +0500 Subject: [PATCH 06/73] M/Aws/CodeBuild-Project-Logging-Enabled --- ...gingEnabled.spec.js => codebuildProjectLoggingEnabled.spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/aws/codebuild/{codeBuildProjectLoggingEnabled.spec.js => codebuildProjectLoggingEnabled.spec.js} (100%) diff --git a/plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js b/plugins/aws/codebuild/codebuildProjectLoggingEnabled.spec.js similarity index 100% rename from plugins/aws/codebuild/codeBuildProjectLoggingEnabled.spec.js rename to plugins/aws/codebuild/codebuildProjectLoggingEnabled.spec.js From c9d96ad09f3e5e3962e0155db317fdd86f550831 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 10 Jun 2024 03:06:31 +0500 Subject: [PATCH 07/73] M/Aws/Api-gateway-request-validation --- exports.js | 1 + helpers/aws/api.js | 6 + helpers/aws/api_multipart.js | 6 + .../apigateway/apigatewayRequestValidation.js | 72 ++++++++ .../apigatewayRequestValidaton.spec.js | 155 ++++++++++++++++++ 5 files changed, 240 insertions(+) create mode 100644 plugins/aws/apigateway/apigatewayRequestValidation.js create mode 100644 plugins/aws/apigateway/apigatewayRequestValidaton.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..16e249ad55 100644 --- a/exports.js +++ b/exports.js @@ -25,6 +25,7 @@ module.exports = { 'customDomainTlsVersion' : require(__dirname + '/plugins/aws/apigateway/customDomainTlsVersion.js'), 'apigatewayDefaultEndpointDisabled' : require(__dirname + '/plugins/aws/apigateway/apigatewayDefaultEndpointDisabled.js'), 'apigatewayAuthorization' : require(__dirname + '/plugins/aws/apigateway/apigatewayAuthorization.js'), + 'apigatewayRequestValidation' : require(__dirname + '/plugins/aws/apigateway/apigatewayRequestValidation.js'), 'restrictExternalTraffic' : require(__dirname + '/plugins/aws/appmesh/restrictExternalTraffic.js'), 'appmeshTLSRequired' : require(__dirname + '/plugins/aws/appmesh/appmeshTLSRequired.js'), diff --git a/helpers/aws/api.js b/helpers/aws/api.js index b28dff1cbd..3490e32b0b 100644 --- a/helpers/aws/api.js +++ b/helpers/aws/api.js @@ -1842,6 +1842,12 @@ var postcalls = [ reliesOnCall: 'getRestApis', filterKey: 'restApiId', filterValue: 'id' + }, + getRequestValidators: { + reliesOnService: 'apigateway', + reliesOnCall: 'getRestApis', + filterKey: 'restApiId', + filterValue: 'id' } }, AppConfig: { diff --git a/helpers/aws/api_multipart.js b/helpers/aws/api_multipart.js index 9389518a67..7ae512be79 100644 --- a/helpers/aws/api_multipart.js +++ b/helpers/aws/api_multipart.js @@ -1199,6 +1199,12 @@ var postcalls = [ reliesOnCall: 'getRestApis', filterKey: 'restApiId', filterValue: 'id' + }, + getRequestValidators: { + reliesOnService: 'apigateway', + reliesOnCall: 'getRestApis', + filterKey: 'restApiId', + filterValue: 'id' } }, AppConfig: { diff --git a/plugins/aws/apigateway/apigatewayRequestValidation.js b/plugins/aws/apigateway/apigatewayRequestValidation.js new file mode 100644 index 0000000000..608c45310d --- /dev/null +++ b/plugins/aws/apigateway/apigatewayRequestValidation.js @@ -0,0 +1,72 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'API Gateway Request validation', + category: 'API Gateway', + domain: 'Availability', + severity: 'Medium', + description: 'Ensures that Amazon API Gateway method has request validation enabled.', + more_info: 'Enabling request validation for API Gateway allows to perform basic validation of an API request before proceeding with the integration request. When request validation fails, API Gateway immediately fails the request reduceing unnecessary calls to the backend.', + recommended_action: 'Modify API Gateway configuration and ensure that appropriate request validators are set up for each API.', + link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html', + apis: ['APIGateway:getRestApis', 'APIGateway:getRequestValidators'], + realtime_triggers: ['apigateway:CreateRestApi','apigateway:DeleteRestApi','apigateway:ImportRestApi','apigateway:CreateAuthorizer','apigateway:DeleteAuthorizer'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + var awsOrGov = helpers.defaultPartition(settings); + + async.each(regions.apigateway, function(region, rcb){ + var getRestApis = helpers.addSource(cache, source, + ['apigateway', 'getRestApis', region]); + + if (!getRestApis) return rcb(); + + if (getRestApis.err || !getRestApis.data) { + helpers.addResult(results, 3, + `Unable to query for API Gateway Rest APIs: ${helpers.addError(getRestApis)}`, region); + return rcb(); + } + + if (!getRestApis.data.length) { + helpers.addResult(results, 0, 'No API Gateway Rest APIs found', region); + return rcb(); + } + + getRestApis.data.forEach(api => { + if (!api.id) return; + + var apiArn = `arn:${awsOrGov}:apigateway:${region}::/restapis/${api.id}`; + + var getRequestValidators = helpers.addSource(cache, source, + ['apigateway', 'getRequestValidators', region, api.id]); + + if (!getRequestValidators || getRequestValidators.err || !getRequestValidators.data || !getRequestValidators.data.items) { + helpers.addResult(results, 3, + `Unable to query for API Gateway Request Validators: ${helpers.addError(getRequestValidators)}`, + region, apiArn); + return; + } + + if (!getRequestValidators.data.items.length) { + helpers.addResult(results, 2, + 'No request validators found for API Gateway Rest API', + region, apiArn ); + } else { + helpers.addResult(results, 0, + 'Request validators found for API Gateway Rest API', + region, apiArn); + } + }); + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; + + \ No newline at end of file diff --git a/plugins/aws/apigateway/apigatewayRequestValidaton.spec.js b/plugins/aws/apigateway/apigatewayRequestValidaton.spec.js new file mode 100644 index 0000000000..debe9d3f9b --- /dev/null +++ b/plugins/aws/apigateway/apigatewayRequestValidaton.spec.js @@ -0,0 +1,155 @@ +var expect = require('chai').expect; +var apigatewayRequestValidation = require('./apigatewayRequestValidation'); + +const createCache = (getRestApisData, getRequestValidatorsData) => { + if (getRestApisData && getRestApisData.length && getRestApisData[0].id) var restApiId = getRestApisData[0].id; + return { + apigateway: { + getRestApis: { + 'us-east-1': { + data: getRestApisData + } + }, + getRequestValidators: { + 'us-east-1': { + [restApiId]: { + data: { + items: getRequestValidatorsData + } + } + } + } + } + }; +}; + +const createErrorCache = () => { + return { + apigateway: { + getRestApis: { + 'us-east-1': { + err: { + message: 'error fetching API Gateway Rest APIs' + }, + }, + }, + getRequestValidators: { + 'us-east-1': { + err: { + message: 'error fetching API Gateway Request Validators' + }, + }, + } + + }, + }; +}; + +const createNullCache = () => { + return { + apigateway: { + getRestApis: { + 'us-east-1': null + }, + getRequestValidators: { + 'us-east-1': null + } + } + }; +}; + +describe('apigatewayRequestValidation', function () { + describe('run', function () { + it('should return UNKNOWN if unable to query for API Gateway Rest APIs', function (done) { + const cache = createErrorCache(); + apigatewayRequestValidation.run(cache, {} , (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].region).to.equal('us-east-1'); + expect (results[0].message).to.include('Unable to query for API Gateway Rest APIs:'); + done(); + }); + }); + + it('should return PASS if no API Gateway Rest APIs found', function (done) { + const cache = createCache([]); + apigatewayRequestValidation.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect (results[0].message).to.include('No API Gateway Rest APIs found'); + done(); + }); + }); + + it('should return FAIL if no request validators exist for API Gateway Rest API', function (done) { + const getRestApisData = [ + { + id: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + const getRequestValidatorsData = []; + const cache = createCache(getRestApisData, getRequestValidatorsData); + apigatewayRequestValidation.run(cache,{}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].region).to.equal('us-east-1'); + expect (results[0].message).to.include('No request validators found for API Gateway Rest API'); + done(); + }); + }); + + it('should return PASS if validators exist for API Gateway Rest API', function (done) { + const getRestApisData = [ + { + id: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + const getRequestValidatorsData = [ + [ + { + id: "70wn19", + name: "Validate body", + validateRequestBody: true, + validateRequestParameters: false, + }, + { + id: "z06eap", + name: "Validate query string parameters and headers", + validateRequestBody: false, + validateRequestParameters: true, + }, + ] + ]; + const cache = createCache(getRestApisData, getRequestValidatorsData); + apigatewayRequestValidation.run(cache,{}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Request validators found for API Gateway Rest API') + done(); + }); + }); + it('should not return anything if get Rest APIs response is not found', function (done) { + const cache = createNullCache(); + apigatewayRequestValidation.run(cache, {}, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + }); +}); From 6e41592547641ba1f59611ebd1210cc371e1f924 Mon Sep 17 00:00:00 2001 From: alphadev4 Date: Wed, 12 Jun 2024 16:03:16 +0500 Subject: [PATCH 08/73] Batch Account Has Tags --- exports.js | 1 + .../batchAccounts/batchAccountsHasTags.js | 52 ++++++++++ .../batchAccountsHasTags.spec.js | 94 +++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 plugins/azure/batchAccounts/batchAccountsHasTags.js create mode 100644 plugins/azure/batchAccounts/batchAccountsHasTags.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..2180209e27 100644 --- a/exports.js +++ b/exports.js @@ -1181,6 +1181,7 @@ module.exports = { 'batchAccountCmkEncrypted' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountCmkEncrypted.js'), 'batchAccountDiagnosticLogs' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountDiagnosticLogs.js'), + 'batchAccountsHasTags' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountsHasTags.js'), 'accountCMKEncrypted' : require(__dirname + '/plugins/azure/openai/accountCMKEncrypted.js'), 'accountManagedIdentity' : require(__dirname + '/plugins/azure/openai/accountManagedIdentity.js'), diff --git a/plugins/azure/batchAccounts/batchAccountsHasTags.js b/plugins/azure/batchAccounts/batchAccountsHasTags.js new file mode 100644 index 0000000000..6651dc08a0 --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsHasTags.js @@ -0,0 +1,52 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure/'); + +module.exports = { + title: 'Batch Account Has Tags', + category: 'Batch', + domain: 'Compute', + severity: 'Low', + description: 'Ensures that Batch account have tags associated.', + more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', + recommended_action: 'Modify Batch Account and add tags.', + link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal', + apis: ['batchAccounts:list','diagnosticSettings:listByBatchAccounts'], + realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.batchAccounts, function(location, rcb){ + + var batchAccounts = helpers.addSource(cache, source, + ['batchAccounts', 'list', location]); + + if (!batchAccounts) return rcb(); + + if (batchAccounts.err || !batchAccounts.data) { + helpers.addResult(results, 3, 'Unable to query for Batch accounts: ' + helpers.addError(batchAccounts), location); + return rcb(); + } + if (!batchAccounts.data.length) { + helpers.addResult(results, 0, 'No existing Batch accounts found', location); + return rcb(); + } + + for (let batchAccount of batchAccounts.data) { + if (!batchAccount.id) continue; + + if (batchAccount.tags && Object.entries(batchAccount.tags).length > 0 ) { + helpers.addResult(results, 0, 'Batch account has tags associated', location, batchAccount.id); + } else { + helpers.addResult(results, 2, 'Batch account does not have tags associated', location, batchAccount.id); + } + + } + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/batchAccounts/batchAccountsHasTags.spec.js b/plugins/azure/batchAccounts/batchAccountsHasTags.spec.js new file mode 100644 index 0000000000..4dcd9fb6dd --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsHasTags.spec.js @@ -0,0 +1,94 @@ + +var expect = require('chai').expect; +var batchAccountsHasTags = require('./batchAccountsHasTags'); + +const batchAccounts = [ + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + "tags": { "key": "value" } + }, + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + }, +]; + +const createCache = (batchAccounts) => { + return { + batchAccounts: { + list: { + 'eastus': { + data: batchAccounts + } + } + } + } +}; + +const createErrorCache = () => { + return { + batchAccounts: { + list: { + 'eastus': {} + } + } + }; +}; + +describe('batchAccountsHasTags', function () { + describe('run', function () { + + it('should give unknown result if unable to query for Batch accounts:', function (done) { + const cache = createCache(null); + batchAccountsHasTags.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 Batch accounts:'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if no Batch account exist', function (done) { + const cache = createCache([]); + batchAccountsHasTags.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 Batch accounts found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if Batch account has tags associated', function (done) { + const cache = createCache([batchAccounts[0]]); + batchAccountsHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Batch account has tags associated'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if Batch account does not have tags associated', function (done) { + const cache = createCache([batchAccounts[1]]); + batchAccountsHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Batch account does not have tags associated'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From c6605931084f459264a499510cf37b7226e6068d Mon Sep 17 00:00:00 2001 From: fatima99s Date: Wed, 12 Jun 2024 21:19:56 +0500 Subject: [PATCH 09/73] F/AWS-HealthLakeHasTags --- exports.js | 1 + plugins/aws/healthlake/dataStoreHasTags.js | 51 +++++++ .../aws/healthlake/dataStoreHasTags.spec.js | 128 ++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 plugins/aws/healthlake/dataStoreHasTags.js create mode 100644 plugins/aws/healthlake/dataStoreHasTags.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..ad51d25d45 100644 --- a/exports.js +++ b/exports.js @@ -615,6 +615,7 @@ module.exports = { 'pipelineArtifactsEncrypted' : require(__dirname + '/plugins/aws/codepipeline/pipelineArtifactsEncrypted.js'), 'dataStoreEncrypted' : require(__dirname + '/plugins/aws/healthlake/dataStoreEncrypted.js'), + 'dataStoreHasTags' : require(__dirname + '/plugins/aws/healthlake/dataStoreHasTags.js'), 'codeartifactDomainEncrypted' : require(__dirname + '/plugins/aws/codeartifact/codeartifactDomainEncrypted.js'), diff --git a/plugins/aws/healthlake/dataStoreHasTags.js b/plugins/aws/healthlake/dataStoreHasTags.js new file mode 100644 index 0000000000..8aff99bc3b --- /dev/null +++ b/plugins/aws/healthlake/dataStoreHasTags.js @@ -0,0 +1,51 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'HealthLake Data Store Has Tags', + category: 'AI & ML', + domain: 'Content Delivery', + severity: 'Low', + description: 'Ensure that HealthLake data stores have tags associated.', + more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', + recommended_action: 'Modify HealthLake data store and add tags.', + link: '', + apis: ['HealthLake:listFHIRDatastores', 'ResourceGroupsTaggingAPI:getResources'], + realtime_triggers: ['healthlake:CreateFHIRDatastore', 'healthlake:DeleteFHIRDatastore'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + async.each(regions.healthlake, function(region, rcb){ + var listFHIRDatastores = helpers.addSource(cache, source, + ['healthlake', 'listFHIRDatastores', region]); + + if (!listFHIRDatastores) return rcb(); + + if (listFHIRDatastores.err || !listFHIRDatastores.data) { + helpers.addResult(results, 3, `Unable to query HealthLake Data Store: ${helpers.addError(listFHIRDatastores)}`, region); + return rcb(); + } + + if (!listFHIRDatastores.data.length) { + helpers.addResult(results, 0, 'No HealthLake data stores found', region); + return rcb(); + } + + const arnList = []; + for (let datastore of listFHIRDatastores.data){ + if (!datastore.DatastoreArn) continue; + + arnList.push(datastore.DatastoreArn); + } + + helpers.checkTags(cache, 'Healthlake data store', arnList, region, results, settings); + return rcb(); + + }, function(){ + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/aws/healthlake/dataStoreHasTags.spec.js b/plugins/aws/healthlake/dataStoreHasTags.spec.js new file mode 100644 index 0000000000..a83e8f8f12 --- /dev/null +++ b/plugins/aws/healthlake/dataStoreHasTags.spec.js @@ -0,0 +1,128 @@ +var expect = require('chai').expect; +const dataStoreHasTags = require('./dataStoreHasTags'); + +const listFHIRDatastores = [ + { + "DatastoreId": "7ad17b6c9d48056865a8800b86cc2797", + "DatastoreArn": "arn:aws:healthlake:us-east-1:000111222333:datastore/fhir/7ad17b6c9d48056865a8800b86cc2797", + "DatastoreName": "sadeed-ds1", + "DatastoreStatus": "ACTIVE", + "CreatedAt": "2021-11-23T15:31:55.180000+05:00", + "DatastoreTypeVersion": "R4", + "DatastoreEndpoint": "https://healthlake.us-east-1.amazonaws.com/datastore/7ad17b6c9d48056865a8800b86cc2797/r4/", + "SseConfiguration": { + "KmsEncryptionConfig": { + "CmkType": "CUSTOMER_MANAGED_KMS_KEY", + "KmsKeyId": "arn:aws:kms:us-east-1:000111222333:key/ad013a33-b01d-4d88-ac97-127399c18b3e" + } + } + }, + { + "DatastoreId": "7ad17b6c9d48056865a8800b86cc2797", + "DatastoreArn": "arn:aws:healthlake:us-east-1:000111222333:datastore/fhir/7ad17b6c9d48056865a880", + "DatastoreName": "sadeed-ds1", + "DatastoreStatus": "ACTIVE", + "CreatedAt": "2021-11-23T15:31:55.180000+05:00", + "DatastoreTypeVersion": "R4", + "DatastoreEndpoint": "https://healthlake.us-east-1.amazonaws.com/datastore/7ad17b6c9d48056865a8800b86cc2797/r4/", + "SseConfiguration": { + "KmsEncryptionConfig": { + "CmkType": "CUSTOMER_MANAGED_KMS_KEY", + "KmsKeyId": "arn:aws:kms:us-east-1:000111222333:key/ad013a33-b01d-4d88-ac97-127399c18b3e" + } + } + }, +]; + +const getResources = [ + { + "ResourceARN": "arn:aws:healthlake:us-east-1:000111222333:datastore/fhir/7ad17b6c9d48056865a880", + "Tags": [], + }, + { + "ResourceARN": "arn:aws:healthlake:us-east-1:000111222333:datastore/fhir/7ad17b6c9d48056865a8800b86cc2797", + "Tags": [{key: 'value'}], + } +] + + +const createCache = (datastore, rgData) => { + return { + healthlake: { + listFHIRDatastores: { + 'us-east-1': { + err: null, + data: datastore + }, + }, + }, + resourcegroupstaggingapi: { + getResources: { + 'us-east-1':{ + err: null, + data: rgData + } + } + }, + }; +}; + + +describe('dataStoreHasTags', function () { + describe('run', function () { + it('should PASS if Bedrock custom model has tags', function (done) { + const cache = createCache([listFHIRDatastores[0]], [getResources[1]]); + dataStoreHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Healthlake data store has tags') + done(); + }); + }); + + it('should FAIL if Bedrock custom model doesnot have tags', function (done) { + const cache = createCache([listFHIRDatastores[0]], [getResources[0]]); + dataStoreHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Healthlake data store does not have any tags') + done(); + }); + }); + + it('should PASS if no Bedrock custom model found', function (done) { + const cache = createCache([]); + dataStoreHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('No HealthLake data stores found'); + done(); + }); + }); + + it('should UNKNOWN if unable to query Bedrock custom model', function (done) { + const cache = createCache(null, null); + dataStoreHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Unable to query HealthLake Data Store: ') + done(); + }); + }); + + it('should give unknown result if unable to query resource group tagging api', function (done) { + const cache = createCache([listFHIRDatastores[0]],null); + dataStoreHasTags.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Unable to query all resources') + done(); + }); + }); + }); +}); From acc96ab4aeba895436f41bcef90015e9760423ed Mon Sep 17 00:00:00 2001 From: fatima99s Date: Wed, 12 Jun 2024 21:23:36 +0500 Subject: [PATCH 10/73] F/AWS-HealthLakeHasTags --- plugins/aws/healthlake/dataStoreHasTags.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aws/healthlake/dataStoreHasTags.js b/plugins/aws/healthlake/dataStoreHasTags.js index 8aff99bc3b..4ba8b2bdd5 100644 --- a/plugins/aws/healthlake/dataStoreHasTags.js +++ b/plugins/aws/healthlake/dataStoreHasTags.js @@ -9,9 +9,9 @@ module.exports = { description: 'Ensure that HealthLake data stores have tags associated.', more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', recommended_action: 'Modify HealthLake data store and add tags.', - link: '', + link: 'https://docs.aws.amazon.com/healthlake/latest/devguide/add-a-tag.html', apis: ['HealthLake:listFHIRDatastores', 'ResourceGroupsTaggingAPI:getResources'], - realtime_triggers: ['healthlake:CreateFHIRDatastore', 'healthlake:DeleteFHIRDatastore'], + realtime_triggers: ['healthlake:CreateFHIRDatastore', 'healthlake:DeleteFHIRDatastore', 'healthlake:TagResource', 'healthlake:UntagResource'], run: function(cache, settings, callback) { var results = []; From 65f31aa9f0f568be350d11c7bafb976657f651db Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 12 Jun 2024 21:49:38 +0500 Subject: [PATCH 11/73] Plugin Batch Account AAD Auth enabled --- exports.js | 1 + .../batchAccounts/batchAccountsAADEnabled.js | 64 +++++++++++++ .../batchAccountsAADEnabled.spec.js | 94 +++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 plugins/azure/batchAccounts/batchAccountsAADEnabled.js create mode 100644 plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..e8468527cc 100644 --- a/exports.js +++ b/exports.js @@ -1181,6 +1181,7 @@ module.exports = { 'batchAccountCmkEncrypted' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountCmkEncrypted.js'), 'batchAccountDiagnosticLogs' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountDiagnosticLogs.js'), + 'batchAccountsAADEnabled' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountsAADEnabled.js'), 'accountCMKEncrypted' : require(__dirname + '/plugins/azure/openai/accountCMKEncrypted.js'), 'accountManagedIdentity' : require(__dirname + '/plugins/azure/openai/accountManagedIdentity.js'), diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js new file mode 100644 index 0000000000..3987251a7f --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -0,0 +1,64 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure/'); + +module.exports = { + title: 'Batch Account AAD Auth Enabled', + category: 'Batch', + domain: 'Compute', + severity: 'Medium', + description: 'Ensures that Batch account has AAD authentication mode enabled.', + more_info: 'Enabling AAD Authentication for your Azure Batch Account ensures enhanced security by utilizing a robust authentication method required for several security-related features. By restricting the service API authentication to Microsoft Entra ID, you prevent access through less secure shared key methods, thereby safeguarding your batch resources from unauthorized access.', + recommended_action: 'Enable diagnostic logging for all Batch accounts.', + link: 'https://learn.microsoft.com/en-us/azure/batch/security-best-practices#batch-account-authentication', + apis: ['batchAccounts:list'], + realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.batchAccounts, function(location, rcb){ + + var batchAccounts = helpers.addSource(cache, source, + ['batchAccounts', 'list', location]); + + if (!batchAccounts) return rcb(); + + if (batchAccounts.err || !batchAccounts.data) { + helpers.addResult(results, 3, 'Unable to query for Batch accounts: ' + helpers.addError(batchAccounts), location); + return rcb(); + } + if (!batchAccounts.data.length) { + helpers.addResult(results, 0, 'No existing Batch accounts found', location); + return rcb(); + } + + for (let batchAccount of batchAccounts.data) { + if (!batchAccount.id) continue; + + let found = false; + if (batchAccount.allowedAuthenticationModes && + batchAccount.allowedAuthenticationModes.length) { + batchAccount.allowedAuthenticationModes.forEach(mode => { + if (mode.toUpperCase() == 'AAD') { + found = true; + } + }); + + if (found) { + helpers.addResult(results, 0, 'Batch account is configured with AAD Authentication', location, batchAccount.id); + } else { + helpers.addResult(results, 2, 'Batch account is not configured with AAD Authentication', location, batchAccount.id); + } + } else { + helpers.addResult(results, 2, 'Batch account is not configured with AAD Authentication', location, batchAccount.id); + } + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js new file mode 100644 index 0000000000..0cc332ea70 --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js @@ -0,0 +1,94 @@ + +var expect = require('chai').expect; +var batchAccountsAADEnabled = require('./batchAccountsAADEnabled'); + +const batchAccounts = [ + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + "allowedAuthenticationModes": ["SharedKey", "AAD", "TaskAuthenticationToken"] + }, + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + }, +]; + +const createCache = (batchAccounts) => { + return { + batchAccounts: { + list: { + 'eastus': { + data: batchAccounts + } + } + } + } +}; + +const createErrorCache = () => { + return { + batchAccounts: { + list: { + 'eastus': {} + } + } + }; +}; + +describe('batchAccountsAADEnabled', function () { + describe('run', function () { + + it('should give unknown result if unable to query for Batch accounts:', function (done) { + const cache = createCache(null); + batchAccountsAADEnabled.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 Batch accounts:'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if no Batch account exist', function (done) { + const cache = createCache([]); + batchAccountsAADEnabled.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 Batch accounts found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if Batch account is configured with AAD Authentication', function (done) { + const cache = createCache([batchAccounts[0]]); + batchAccountsAADEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Batch account is configured with AAD Authentication'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if Batch account is not configured with AAD Authentication', function (done) { + const cache = createCache([batchAccounts[1]]); + batchAccountsAADEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Batch account is not configured with AAD Authentication'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From e7c0d9c9edc96ea257316f6d4cb7847c083967ce Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 12 Jun 2024 21:52:55 +0500 Subject: [PATCH 12/73] Plugin Batch Account Public Access --- exports.js | 1 + .../batchAccountsPublicAccess.js | 53 +++++++++++ .../batchAccountsPublicAccess.spec.js | 95 +++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 plugins/azure/batchAccounts/batchAccountsPublicAccess.js create mode 100644 plugins/azure/batchAccounts/batchAccountsPublicAccess.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..d751c5bf70 100644 --- a/exports.js +++ b/exports.js @@ -1181,6 +1181,7 @@ module.exports = { 'batchAccountCmkEncrypted' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountCmkEncrypted.js'), 'batchAccountDiagnosticLogs' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountDiagnosticLogs.js'), + 'batchAccountsPublicAccess' : require(__dirname + '/plugins/azure/batchAccounts/batchAccountsPublicAccess.js'), 'accountCMKEncrypted' : require(__dirname + '/plugins/azure/openai/accountCMKEncrypted.js'), 'accountManagedIdentity' : require(__dirname + '/plugins/azure/openai/accountManagedIdentity.js'), diff --git a/plugins/azure/batchAccounts/batchAccountsPublicAccess.js b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js new file mode 100644 index 0000000000..76e15efddb --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js @@ -0,0 +1,53 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure/'); + +module.exports = { + title: 'Batch Account Public Access', + category: 'Batch', + domain: 'Compute', + severity: 'Medium', + description: 'Ensures that Batch account are not publicly accessible.', + more_info: 'Disabling public access for your Azure Batch Account enhances security by restricting unauthorized access to your batch resources. This setting ensures that only trusted, internal sources can interact with your batch services, protecting your data and processes from potential external threats.', + recommended_action: 'Modify Batch Account and disable public access.', + link: 'https://learn.microsoft.com/en-us/azure/batch/public-network-access', + apis: ['batchAccounts:list'], + realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.batchAccounts, function(location, rcb){ + + var batchAccounts = helpers.addSource(cache, source, + ['batchAccounts', 'list', location]); + + if (!batchAccounts) return rcb(); + + if (batchAccounts.err || !batchAccounts.data) { + helpers.addResult(results, 3, 'Unable to query for Batch accounts: ' + helpers.addError(batchAccounts), location); + return rcb(); + } + if (!batchAccounts.data.length) { + helpers.addResult(results, 0, 'No existing Batch accounts found', location); + return rcb(); + } + + for (let batchAccount of batchAccounts.data) { + if (!batchAccount.id) continue; + + if (batchAccount.publicNetworkAccess && + batchAccount.publicNetworkAccess.toLowerCase() === 'enabled') { + helpers.addResult(results, 2, 'Batch account is publicly accessible', location, batchAccount.id); + } else { + helpers.addResult(results, 0, 'Batch account is not publicly accessible', location, batchAccount.id); + } + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/batchAccounts/batchAccountsPublicAccess.spec.js b/plugins/azure/batchAccounts/batchAccountsPublicAccess.spec.js new file mode 100644 index 0000000000..ca54e124fe --- /dev/null +++ b/plugins/azure/batchAccounts/batchAccountsPublicAccess.spec.js @@ -0,0 +1,95 @@ + +var expect = require('chai').expect; +var batchAccountsPublicAccess = require('./batchAccountsPublicAccess'); + +const batchAccounts = [ + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + "publicNetworkAccess": "Disabled" + }, + { + "id": "/subscriptions/1234566/resourceGroups/dummy/providers/Microsoft.Batch/batchAccounts/test", + "name": "test", + "type": "Microsoft.Batch/batchAccounts", + "location": "eastus", + "accountEndpoint": "test.eastus.batch.azure.com", + "nodeManagementEndpoint": "123456789.eastus.service.batch.azure.com", + "publicNetworkAccess": "Enabled" + }, +]; + +const createCache = (batchAccounts) => { + return { + batchAccounts: { + list: { + 'eastus': { + data: batchAccounts + } + } + } + } +}; + +const createErrorCache = () => { + return { + batchAccounts: { + list: { + 'eastus': {} + } + } + }; +}; + +describe('batchAccountsPublicAccess', function () { + describe('run', function () { + + it('should give unknown result if unable to query for Batch accounts:', function (done) { + const cache = createCache(null); + batchAccountsPublicAccess.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 Batch accounts:'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if no Batch account exist', function (done) { + const cache = createCache([]); + batchAccountsPublicAccess.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 Batch accounts found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if Batch account is not publicly accessible', function (done) { + const cache = createCache([batchAccounts[0]]); + batchAccountsPublicAccess.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Batch account is not publicly accessible'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if Batch account is publicly accessible', function (done) { + const cache = createCache([batchAccounts[1]]); + batchAccountsPublicAccess.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Batch account is publicly accessible'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From d18f0592eafa3da98c9004e3e0b4ddaba33d57df Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 12 Jun 2024 22:08:10 +0500 Subject: [PATCH 13/73] Plugin Event Hub Namespace auto-inflate enabled --- exports.js | 1 + .../eventhub/eventHubamespaceAutoInflate.js | 60 ++++++++++ .../eventHubamespaceAutoInflate.spec.js | 112 ++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 plugins/azure/eventhub/eventHubamespaceAutoInflate.js create mode 100644 plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..310e7b25b5 100644 --- a/exports.js +++ b/exports.js @@ -1109,6 +1109,7 @@ module.exports = { 'eventHubMinimumTLSversion' : require(__dirname + '/plugins/azure/eventhub/eventHubMinimumTLSversion.js'), 'eventHubNamespaceHasTags' : require(__dirname + '/plugins/azure/eventhub/eventHubNamespaceHasTags.js'), + 'eventHubamespaceAutoInflate' : require(__dirname + '/plugins/azure/eventhub/eventHubamespaceAutoInflate.js'), 'eventHubLocalAuthDisabled' : require(__dirname + '/plugins/azure/eventhub/eventHubLocalAuthDisabled.js'), 'eventHubPublicAccess' : require(__dirname + '/plugins/azure/eventhub/eventHubPublicAccess.js'), 'eventHubNamespaceCmkEncrypted' : require(__dirname + '/plugins/azure/eventhub/eventHubNamespaceCmkEncrypted.js'), diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js new file mode 100644 index 0000000000..609b230f56 --- /dev/null +++ b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js @@ -0,0 +1,60 @@ + +var async = require('async'); +const helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'Event Hubs Namespace Auto Inflate Enabled', + category: 'Event Hubs', + domain: 'Content Delivery', + severity: 'Low', + description: 'Ensure that Event Hubs namespace have Auto Inflate feature enabled', + more_info: 'Enabling Auto-inflate for your Azure Event Hubs namespace ensures seamless scaling by automatically adjusting the number of throughput units (TUs) based on workload demands. This feature helps prevent throttling issues by scaling up as needed, providing efficient and reliable data handling without manual intervention.', + recommended_action: 'Modify Event Hub namespace and enable auto-inflate feature.', + link: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate', + apis: ['eventHub:listEventHub'], + realtime_triggers: ['microsofteventhub:namespaces:write', 'microsofteventhub:namespaces:delete'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var locations = helpers.locations(settings.govcloud); + + async.each(locations.eventHub, function(location, rcb) { + var eventHubs = helpers.addSource(cache, source, + ['eventHub', 'listEventHub', location]); + + if (!eventHubs) return rcb(); + + if (eventHubs.err || !eventHubs.data) { + helpers.addResult(results, 3, + 'Unable to query for Event Hubs namespaces: ' + helpers.addError(eventHubs), location); + return rcb(); + } + + if (!eventHubs.data.length) { + helpers.addResult(results, 0, 'No Event Hubs namespaces found', location); + return rcb(); + } + + for (let eventHub of eventHubs.data){ + if (!eventHub.id) continue; + + if (eventHub.sku && + eventHub.sku.tier && + eventHub.sku.tier.toLowerCase() != 'standard') continue; + + if (eventHub.isAutoInflateEnabled){ + helpers.addResult(results, 0, + 'Event Hubs namespace has auto inflate feature enabled',location, eventHub.id); + } else { + helpers.addResult(results, 2, + 'Event Hubs namespace does not have auto inflate feature enabled', location, eventHub.id); + } + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js b/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js new file mode 100644 index 0000000000..b5c4dd3f26 --- /dev/null +++ b/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js @@ -0,0 +1,112 @@ +var expect = require('chai').expect; +var eventHubamespaceAutoInflate = require('./eventHubamespaceAutoInflate'); + +const eventHubs = [ + { + "kind": "v12.0", + "location": "eastus", + "tags": {}, + "id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.EventHub/namespaces/testHub'", + "name": "testHub", + "type": 'Microsoft.EventHub/Namespaces', + "location": 'East US', + "tags": {}, + "minimumTlsVersion": '1.2', + "publicNetworkAccess": 'Enabled', + "disableLocalAuth": true, + "zoneRedundant": true, + "isAutoInflateEnabled": true, + "maximumThroughputUnits": 0, + "kafkaEnabled": false, + "identity": { + "principalId": "12345", + "tenantId": "123243546", + "type": "SystemAssigned" + }, + }, + { + "kind": "v12.0", + "location": "eastus", + "tags": {}, + "id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.EventHub/namespaces/testHub'", + "name": "testHub", + "type": 'Microsoft.EventHub/Namespaces', + "location": 'East US', + "tags": {}, + "minimumTlsVersion": '1.1', + "publicNetworkAccess": 'Enabled', + "disableLocalAuth": true, + "zoneRedundant": true, + "isAutoInflateEnabled": false, + "maximumThroughputUnits": 0, + "kafkaEnabled": false, + } +]; + +const createCache = (hub) => { + return { + eventHub: { + listEventHub: { + 'eastus': { + data: hub + } + } + } + } +}; + +describe('eventHubamespaceAutoInflate', function() { + describe('run', function() { + it('should give passing result if no event hub 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 Event Hubs namespaces found'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache([]); + eventHubamespaceAutoInflate.run(cache, {}, callback); + }); + + it('should give failing result if Event Hubs namespace does not have auto-inflate feature enabled', 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('Event Hubs namespace does not have auto-inflate feature enabled'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache([eventHubs[1]]); + eventHubamespaceAutoInflate.run(cache, {}, callback); + }); + + it('should give passing result if Event Hubs namespace has auto-inflate feature enabled', 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('Event Hubs namespace has auto-inflate feature enabled'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache([eventHubs[0]]); + eventHubamespaceAutoInflate.run(cache, {}, callback); + }); + + it('should give unknown result if unable to query for event hubs', 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 Event Hubs namespaces:'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache(null); + eventHubamespaceAutoInflate.run(cache, {}, callback); + }); + }) +}) \ No newline at end of file From 1402667486d7fcbc70a4e376a952e98ac2b26f08 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Jun 2024 01:18:27 +0500 Subject: [PATCH 14/73] Document Db Profiler Enabled --- exports.js | 1 + .../documentDB/docdbClusterProfilerEnabled.js | 56 ++++++++++++ .../docdbClusterProfilerEnabled.spec.js | 88 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 plugins/aws/documentDB/docdbClusterProfilerEnabled.js create mode 100644 plugins/aws/documentDB/docdbClusterProfilerEnabled.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..2197443fb4 100644 --- a/exports.js +++ b/exports.js @@ -635,6 +635,7 @@ module.exports = { 'docDbHasTags' : require(__dirname + '/plugins/aws/documentDB/docDbHasTags.js'), 'docdbDeletionProtectionEnabled': require(__dirname + '/plugins/aws/documentDB/docdbDeletionProtectionEnabled.js'), 'docdbClusterBackupRetention' : require(__dirname + '/plugins/aws/documentDB/docdbClusterBackupRetention.js'), + 'docdbClusterProfilerEnabled' : require(__dirname + '/plugins/aws/documentDB/docdbClusterProfilerEnabled.js'), 'instanceMediaStreamsEncrypted' : require(__dirname + '/plugins/aws/connect/instanceMediaStreamsEncrypted.js'), 'instanceTranscriptsEncrypted' : require(__dirname + '/plugins/aws/connect/instanceTranscriptsEncrypted.js'), diff --git a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js new file mode 100644 index 0000000000..0ed6ff5547 --- /dev/null +++ b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js @@ -0,0 +1,56 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'DocumentDB Cluster Profiler Enabled', + category: 'DocumentDB', + domain: 'Databases', + severity: 'Medium', + description: 'Ensure that Amazon DocumentDB clusters have Profiler feature enabled.', + more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps you to monitor and log slow database operations. This makes it easier to identify and fix performance issues by analyzing detailed logs in Amazon CloudWatch.', + recommended_action: 'Modify DocumentDb cluster and enable profiler feature.', + link: 'https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html', + apis: ['DocDB:describeDBClusters'], + realtime_triggers: ['docdb:CreateDBCluster','docdb:ModifyDBCluster','docdb:DeleteDBCluster'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + + async.each(regions.docdb, function(region, rcb){ + var describeDBClusters = helpers.addSource(cache, source, + ['docdb', 'describeDBClusters', region]); + + if (!describeDBClusters) return rcb(); + + if (describeDBClusters.err || !describeDBClusters.data) { + helpers.addResult(results, 3, + `Unable to list DocumentDB clusters: ${helpers.addError(describeDBClusters)}`, region); + return rcb(); + } + + if (!describeDBClusters.data.length) { + helpers.addResult(results, 0, + 'No DocumentDB clusters found', region); + return rcb(); + } + + for (let cluster of describeDBClusters.data) { + if (!cluster.DBClusterArn) continue; + + if (cluster.EnabledCloudwatchLogsExports && + cluster.EnabledCloudwatchLogsExports.length && + cluster.EnabledCloudwatchLogsExports.includes('profiler')) { + helpers.addResult(results, 0, 'DocumentDB cluster has profiler feature enabled', region, cluster.DBClusterArn); + } else { + helpers.addResult(results, 2, 'DocumentDB cluster does not have profiler feature enabled', region, cluster.DBClusterArn); + } + } + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/aws/documentDB/docdbClusterProfilerEnabled.spec.js b/plugins/aws/documentDB/docdbClusterProfilerEnabled.spec.js new file mode 100644 index 0000000000..415457b032 --- /dev/null +++ b/plugins/aws/documentDB/docdbClusterProfilerEnabled.spec.js @@ -0,0 +1,88 @@ +var expect = require('chai').expect; +var docdbProfilerEnabled = require('./docdbClusterProfilerEnabled'); + +const describeDBClusters = [ + { + AvailabilityZones: [], + BackupRetentionPeriod: 1, + DBClusterArn: 'arn:aws:rds:us-east-1:000011112222:cluster:docdb-2021-11-10-10-16-10', + DBClusterIdentifier: 'docdb-2021-11-10-10-16-10', + DBClusterParameterGroup: 'default.docdb4.0', + DBSubnetGroup: 'default-vpc-99de2fe4', + Status: 'available', + DeletionProtection: true, + EnabledCloudwatchLogsExports: [ "audit", "profiler"] + }, + { + AvailabilityZones: [], + BackupRetentionPeriod: 10, + DBClusterArn: 'arn:aws:rds:us-east-1:000011112223:cluster:docdb-2021-11-10-10-16-10', + DBClusterIdentifier: 'docdb-2021-11-10-10-16-10', + DBClusterParameterGroup: 'default.docdb4.0', + DBSubnetGroup: 'default-vpc-99de2fe4', + Status: 'available', + DeletionProtection: false, + EnabledCloudwatchLogsExports: [ "audit"] + } +]; + +const createCache = (clusters, clustersErr) => { + return { + docdb: { + describeDBClusters: { + 'us-east-1': { + err: clustersErr, + data: clusters + }, + }, + } + }; +}; + +describe('docdbProfilerEnabled', function () { + describe('run', function () { + it('should PASS if DocumentDb Cluster has profiler feature enabled', function (done) { + const cache = createCache([describeDBClusters[0]]); + docdbProfilerEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('DocumentDB cluster has profiler feature enabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should FAIL if DocumentDB Clusters does not have profiler feature enabled', function (done) { + const cache = createCache([describeDBClusters[1]]); + docdbProfilerEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('DocumentDB cluster does not have profiler feature enabled'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should PASS if no DocumentDB Clusters found', function (done) { + const cache = createCache([]); + docdbProfilerEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('No DocumentDB clusters found'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + + it('should UNKNOWN if unable to list DocumentDB Clusters', function (done) { + const cache = createCache(null, { message: "Unable to list DocumentDB Clusters encryption" }); + docdbProfilerEnabled.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 list DocumentDB clusters:'); + expect(results[0].region).to.equal('us-east-1'); + done(); + }); + }); + }); +}); From 4769b10a56111751d3e132ec868c1b19228944f7 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 01:48:59 +0500 Subject: [PATCH 15/73] F/AWS-GuarddutyLambdaProtection --- exports.js | 1 + .../aws/guardduty/lambdaProtectionEnabled.js | 69 ++++++ .../guardduty/lambdaProtectionEnabled.spec.js | 218 ++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 plugins/aws/guardduty/lambdaProtectionEnabled.js create mode 100644 plugins/aws/guardduty/lambdaProtectionEnabled.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..0dd8eb13b3 100644 --- a/exports.js +++ b/exports.js @@ -596,6 +596,7 @@ module.exports = { 's3ProtectionEnabled' : require(__dirname + '/plugins/aws/guardduty/s3ProtectionEnabled.js'), 'rdsProtectionEnabled' : require(__dirname + '/plugins/aws/guardduty/rdsProtectionEnabled.js'), 'exportedFindingsEncrypted' : require(__dirname + '/plugins/aws/guardduty/exportedFindingsEncrypted.js'), + 'lambdaProtectionEnabled' : require(__dirname + '/plugins/aws/guardduty/lambdaProtectionEnabled.js'), 'workspacesVolumeEncryption' : require(__dirname + '/plugins/aws/workspaces/workspacesVolumeEncryption.js'), 'workSpacesHealthyInstances' : require(__dirname + '/plugins/aws/workspaces/workSpacesHealthyInstances.js'), diff --git a/plugins/aws/guardduty/lambdaProtectionEnabled.js b/plugins/aws/guardduty/lambdaProtectionEnabled.js new file mode 100644 index 0000000000..0292fb5239 --- /dev/null +++ b/plugins/aws/guardduty/lambdaProtectionEnabled.js @@ -0,0 +1,69 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'GuardDuty Lambda Protection Enabled', + category: 'GuardDuty', + domain: 'Management and Governance', + severity: 'Medium', + description: 'Ensures GuardDuty protection is enabled for Lambda functions.' , + more_info: 'Lambda Protection helps detect potential security threats in your Lambda functions by monitoring network activity logs and generating findings for suspicious traffic.', + recommended_action: 'Enable GuardDuty Lambda protection for all AWS accounts.', + link: 'https://docs.aws.amazon.com/guardduty/latest/ug/lambda-protection.html', + apis: ['GuardDuty:listDetectors', 'GuardDuty:getDetector', 'STS:getCallerIdentity'], + realtime_triggers: ['guardduty:CreateDetector', 'guardduty:UpdateDetector', 'guardduty:DeleteDetector'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + + var acctRegion = helpers.defaultRegion(settings); + var awsOrGov = helpers.defaultPartition(settings); + var accountId = helpers.addSource(cache, source, ['sts', 'getCallerIdentity', acctRegion, 'data']); + + var regions = helpers.regions(settings); + + async.each(regions.guardduty, function(region, rcb) { + var listDetectors = helpers.addSource(cache, source, ['guardduty', 'listDetectors', region]); + + if (!listDetectors) return rcb(); + + if (listDetectors.err || !listDetectors.data) { + helpers.addResult(results, 3, 'Unable to list GuardDuty detectors: ' + helpers.addError(listDetectors), region); + return rcb(); + } + + if (!listDetectors.data || !listDetectors.data.length) { + helpers.addResult(results, 0, 'No GuardDuty detectors found', region); + return rcb(); + } + + listDetectors.data.forEach(function(detectorId) { + + var getDetector = helpers.addSource(cache, source, ['guardduty', 'getDetector', region, detectorId]); + + if (!getDetector) return; + + if (getDetector.err || !getDetector.data) { + helpers.addResult(results, 3, 'Unable to get GuardDuty detector: ' + helpers.addError(getDetector),region); + return; + } + + var detector = getDetector.data; + var resource = `arn:${awsOrGov}:guardduty:${region}:${accountId}:detector/${detector.detectorId}`; + var lambdaLoginEventsFeature = (detector.Features && detector.Features.find(feature => feature.Name === 'LAMBDA_NETWORK_LOGS' && feature.Status === 'ENABLED')) ? true : false; + + if (lambdaLoginEventsFeature) { + helpers.addResult(results, 0, 'GuardDuty lambda protection is enabled' , region, resource); + } else { + helpers.addResult(results, 2, 'GuardDuty lambda protection is disabled ' , region, resource); + } + + }); + + rcb(); + }, function(){ + callback(null, results, source); + }); + } +}; diff --git a/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js b/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js new file mode 100644 index 0000000000..c81f9516d8 --- /dev/null +++ b/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js @@ -0,0 +1,218 @@ +var expect = require('chai').expect; +var lambdaProtectionEnabled = require('./lambdaProtectionEnabled'); + +const listDetectors = [ + "6cc45a4adb18e50f5ba51f6800db03d8" +]; + +const getDetector = [ + { + "CreatedAt": "2021-11-16T15:54:17.530Z", + "FindingPublishingFrequency": "SIX_HOURS", + "ServiceRole": "arn:aws:iam::000011112222:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty", + "Status": "ENABLED", + "UpdatedAt": "2021-12-01T14:13:59.029Z", + "Features": [ + { + "Name": "CLOUD_TRAIL", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "DNS_LOGS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "FLOW_LOGS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "S3_DATA_EVENTS", + "Status": "DISABLED", + "UpdatedAt": "2024-03-25T14:19:28+05:00" + }, + { + "Name": "EKS_AUDIT_LOGS", + "Status": "DISABLED", + "UpdatedAt": "2024-03-25T14:19:34+05:00" + }, + { + "Name": "EBS_MALWARE_PROTECTION", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:14:46+05:00" + }, + { + "Name": "RDS_LOGIN_EVENTS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:40:00+05:00" + }, + { + "Name": "LAMBDA_NETWORK_LOGS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:40:00+05:00" + }, + ], + + "Tags": {} + }, + { + "CreatedAt": "2021-11-16T15:54:17.530Z", + "FindingPublishingFrequency": "SIX_HOURS", + "ServiceRole": "arn:aws:iam::000011112222:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty", + "Status": "ENABLED", + "UpdatedAt": "2021-12-01T14:13:59.029Z", + "Features": [ + { + "Name": "CLOUD_TRAIL", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "DNS_LOGS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "FLOW_LOGS", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:44:02+05:00" + }, + { + "Name": "S3_DATA_EVENTS", + "Status": "DISABLED", + "UpdatedAt": "2024-03-25T14:19:28+05:00" + }, + { + "Name": "EKS_AUDIT_LOGS", + "Status": "DISABLED", + "UpdatedAt": "2024-03-25T14:19:34+05:00" + }, + { + "Name": "EBS_MALWARE_PROTECTION", + "Status": "ENABLED", + "UpdatedAt": "2024-03-25T14:14:46+05:00" + }, + { + "Name": "LAMBDA_NETWORK_LOGS", + "Status": "DISABLED", + "UpdatedAt": "2024-03-25T14:40:00+05:00" + }, + ], + "Tags": {} + } +]; + +const createCache = (listDetectors, getDetector) => { + let detectorId = (listDetectors.length) ? listDetectors[0] : null; + return { + guardduty: { + listDetectors: { + 'us-east-1': { + data: listDetectors + }, + }, + getDetector: { + 'us-east-1': { + [detectorId]: { + data: getDetector + } + } + } + } + }; +}; + +const createErrorCache = () => { + return { + guardduty: { + listDetectors: { + 'us-east-1': { + err: { + message: 'error desribing cache clusters' + }, + }, + }, + }, + }; +}; + +const createNullCache = () => { + return { + guardduty: { + listDetectors: { + 'us-east-1': null + } + } + }; +}; + + +describe('lambdaProtectionEnabled', function () { + describe('run', function () { + it('should FAIL if GuardDuty lambda protection is diabled', function (done) { + const cache = createCache(listDetectors, getDetector[1],); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('GuardDuty lambda protection is disabled'); + done(); + }); + }); + + it('should PASS if GuardDuty lambda protection is enabled', function (done) { + const cache = createCache(listDetectors, getDetector[0]); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('GuardDuty lambda protection is enabled'); + done(); + }); + }); + + it('should PASS if no detectors found', function (done) { + const cache = createCache([]); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('No GuardDuty detectors found'); + done(); + }); + }); + + it('should UNKNOWN unable to list GuardDuty detector', function (done) { + const cache = createErrorCache(); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Unable to list GuardDuty detectors:'); + done(); + }); + }); + + it('should UNKNOWN unable to get GuardDuty detector', function (done) { + const cache = createCache([listDetectors]); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(3); + expect(results[0].region).to.equal('us-east-1'); + expect(results[0].message).to.include('Unable to get GuardDuty detector: '); + done(); + }); + }); + + it('should not return any result if list dectectors response not found', function (done) { + const cache = createNullCache(); + lambdaProtectionEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(0); + done(); + }); + }); + }); +}); + From 9dfec45b23394f1dddd21af88a29a7b20c8de9da Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 03:01:56 +0500 Subject: [PATCH 16/73] F/Azure-mysqlFlexibleServerLatestVersion --- exports.js | 1 + .../mysqlserver/mysqlFlexibleServerVersion.js | 57 ++++++++++ .../mysqlFlexibleServerVersion.spec.js | 100 ++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..4701036ba8 100644 --- a/exports.js +++ b/exports.js @@ -854,6 +854,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), + 'mysqlFlexibleServerVersion' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js new file mode 100644 index 0000000000..2c17595995 --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js @@ -0,0 +1,57 @@ +const async = require('async'); +const helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'MySQL Flexible Server Version', + category: 'MySQL Server', + domain: 'Databases', + severity: 'Medium', + description: 'Ensures that MySQL Flexible Servers are using the latest server version.', + more_info: 'Using the latest version of Upgrade the version of PostgreSQL flexible server to the latest available version. will give access to new software features, resolve reported bugs through security patches, and improve compatibility with other applications and services', + recommended_action: 'Ensure MySQL Flexible Servers are using the latest server version.', + link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/how-to-upgrade', + apis: ['servers:listMysqlFlexibleServer'], + realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete'], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.servers, (location, rcb) => { + const servers = helpers.addSource(cache, source, + ['servers', 'listMysqlFlexibleServer', location]); + + if (!servers) return rcb(); + + if (servers.err || !servers.data) { + helpers.addResult(results, 3, + 'Unable to query for MySQL flexible servers: ' + helpers.addError(servers), location); + return rcb(); + } + + if (!servers.data.length) { + helpers.addResult(results, 0, 'No existing MySQL flexible servers found', location); + return rcb(); + } + + for (var flexibleServer of servers.data) { + if (!flexibleServer.id) return; + + let version = parseFloat(flexibleServer.version); + + if (version && version >= 8.0) { + helpers.addResult(results, 0, + 'MySQL flexible server has latest server version', location, flexibleServer.id); + } else { + helpers.addResult(results, 2, + 'MySQL flexible server does not have latest server version', location, flexibleServer.id); + } + } + rcb(); + }, function() { + // Global checking goes here + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js new file mode 100644 index 0000000000..7b42b881ff --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js @@ -0,0 +1,100 @@ +var assert = require('assert'); +var expect = require('chai').expect; +var auth = require('./mysqlFlexibleServerVersion'); + +const createCache = (err, list) => { + return { + servers: { + listMysqlFlexibleServer: { + 'eastus': { + err: err, + data: list + } + } + } + } +}; + +describe('mysqlFlexibleServersMinTls', function() { + describe('run', function() { + it('should PASS if no existing servers 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 existing MySQL flexible servers found'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [], + {} + ); + + auth.run(cache, {}, callback); + }); + + it('should FAIL if MySQL server is not using latest version', 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('MySQL flexible server does not have latest server version'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [ + { + "id": "/subscriptions/12345/resourceGroups/Default/providers/Microsoft.DBforMySQL/flexibleServers/test-server", + "type": "Microsoft.DBforMySQL/flexibleServers", + "version": '5.8' + } + ], + ); + + auth.run(cache, {}, callback); + }); + + it('should PASS if MySQL server is using latest version', 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('MySQL flexible server has latest server version'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [ + { + "id": "/subscriptions/12345/resourceGroups/Default/providers/Microsoft.DBforMySQL/flexibleServers/test-server", + "type": "Microsoft.DBforMySQL/flexibleServers", + "version": "8.0" + } + ] + ); + + auth.run(cache, {}, callback); + }); + + it('should UNKNOWN if unable to query for server', 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 MySQL flexible servers: '); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, null + ); + + auth.run(cache, {}, callback); + }); + }) +}) \ No newline at end of file From b111cda9f835b8718e7bdf47e67a521776521f01 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 03:35:05 +0500 Subject: [PATCH 17/73] F/Azure-mysqlServerManagedIdentity --- exports.js | 1 + .../mysqlFlexibleServerManagedIdentity.js | 53 +++++++++ ...mysqlFlexibleServerManagedIdentity.spec.js | 103 ++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..253701c18f 100644 --- a/exports.js +++ b/exports.js @@ -855,6 +855,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), + 'mysqlServerManagedIdentity' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerManagedIdentity.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js new file mode 100644 index 0000000000..42d92dc34e --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js @@ -0,0 +1,53 @@ +const async = require('async'); +const helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'MySQL Flexible Server Managed Identity', + category: 'MySQL Server', + domain: 'Databases', + severity: 'Medium', + description: 'Ensures that MySQL Flexible Servers have managed identity enabled.', + more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', + recommended_action: 'Modify MySQL Flexible Server add managed identity.', + link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/how-to-azure-ad', + apis: ['servers:listMysqlFlexibleServer'], + realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete'], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.servers, (location, rcb) => { + const servers = helpers.addSource(cache, source, + ['servers', 'listMysqlFlexibleServer', location]); + + if (!servers) return rcb(); + + if (servers.err || !servers.data) { + helpers.addResult(results, 3, + 'Unable to query for MySQL flexible servers: ' + helpers.addError(servers), location); + return rcb(); + } + + if (!servers.data.length) { + helpers.addResult(results, 0, 'No existing MySQL flexible servers found', location); + return rcb(); + } + + for (var flexibleServer of servers.data) { + if (!flexibleServer.id) return; + + if (flexibleServer.identity) { + helpers.addResult(results, 0, 'MySQL flexible server has managed identity enabled', location, flexibleServer.id); + } else { + helpers.addResult(results, 2, 'MySQL flexible server does not have managed identity enabled', location, flexibleServer.id); + } + } + rcb(); + }, function() { + // Global checking goes here + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js new file mode 100644 index 0000000000..66251a1c15 --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js @@ -0,0 +1,103 @@ +var assert = require('assert'); +var expect = require('chai').expect; +var auth = require('./mysqlFlexibleServerManagedIdentity'); + +const createCache = (err, list) => { + return { + servers: { + listMysqlFlexibleServer: { + 'eastus': { + err: err, + data: list + } + } + } + } +}; + +describe('mysqlFlexibleServersMinTls', function() { + describe('run', function() { + it('should PASS if no existing servers 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 existing MySQL flexible servers found'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [], + {} + ); + + auth.run(cache, {}, callback); + }); + + it('should FAIL if MySQL server does not have managed identity', 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('MySQL flexible server does not have managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [ + { + "id": "/subscriptions/12345/resourceGroups/Default/providers/Microsoft.DBforMySQL/flexibleServers/test-server", + "type": "Microsoft.DBforMySQL/flexibleServers", + "version": '5.8' + } + ], + ); + + auth.run(cache, {}, callback); + }); + + it('should PASS if MySQL server is using latest version', 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('MySQL flexible server has managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, + [ + { + "id": "/subscriptions/12345/resourceGroups/Default/providers/Microsoft.DBforMySQL/flexibleServers/test-server", + "type": "Microsoft.DBforMySQL/flexibleServers", + "version": "8.0", + "identity": { + "type": "userassigned" + } + } + ] + ); + + auth.run(cache, {}, callback); + }); + + it('should UNKNOWN if unable to query for server', 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 MySQL flexible servers: '); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache( + null, null + ); + + auth.run(cache, {}, callback); + }); + }) +}) \ No newline at end of file From e011374b4e115e8da763681770a98a33d78e0edf Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 04:03:35 +0500 Subject: [PATCH 18/73] F/Azure-mysqlFlexibleServerLogs --- exports.js | 1 + helpers/azure/api.js | 7 +- .../mysqlFlexibleServerLogsEnabled.js | 65 +++++++++ .../mysqlFlexibleServerLogsEnabled.spec.js | 125 ++++++++++++++++++ 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js create mode 100644 plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..80c941a46e 100644 --- a/exports.js +++ b/exports.js @@ -852,6 +852,7 @@ module.exports = { 'resourceAllowedLocations' : require(__dirname + '/plugins/azure/policyservice/resourceAllowedLocations.js'), 'resourceLocationMatch' : require(__dirname + '/plugins/azure/policyservice/resourceLocationMatch.js'), + 'mysqlFlexibleServerLogsEnabled': require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js'), 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), diff --git a/helpers/azure/api.js b/helpers/azure/api.js index 150b7491a2..53aa50ce79 100644 --- a/helpers/azure/api.js +++ b/helpers/azure/api.js @@ -1261,7 +1261,12 @@ var tertiarycalls = { reliesOnPath: 'batchAccounts.list', properties: ['id'], url: 'https://management.azure.com/{id}/providers/microsoft.insights/diagnosticSettings?api-version=2021-05-01-preview' - } + }, + listByMysqlFlexibleServer: { + reliesOnPath: 'servers.listMysqlFlexibleServer', + properties: ['id'], + url: 'https://management.azure.com/{id}/providers/microsoft.insights/diagnosticSettings?api-version=2021-05-01-preview' + }, }, backupShortTermRetentionPolicies: { listByDatabase: { diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js b/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js new file mode 100644 index 0000000000..637bc54e6c --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js @@ -0,0 +1,65 @@ +const async = require('async'); +const helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'MySQL Flexible Server Logging Enabled', + category: 'MySQL Server', + domain: 'Databases', + severity: 'Medium', + description: 'Ensures diagnostic logging is enabled for MySQL Flexible server.', + more_info: 'Enabling diagnostic logging for Azure Database for MySQL Flexible servers helps with performance monitoring, troubleshooting, and security optimization.', + recommended_action: 'Enable diagnostic logging for all MySQL Flexible Servers.', + link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/tutorial-configure-audit', + apis: ['servers:listMysqlFlexibleServer', 'diagnosticSettings:listByMysqlFlexibleServer'], + realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete', 'microsoftinsights:diagnosticsettings:write','microsoftinsights:diagnosticsettings:delete'], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.servers, (location, rcb) => { + + const servers = helpers.addSource(cache, source, + ['servers', 'listMysqlFlexibleServer', location]); + + if (!servers) return rcb(); + + if (servers.err || !servers.data) { + helpers.addResult(results, 3, + 'Unable to query for MySQL flexible servers: ' + helpers.addError(servers), location); + return rcb(); + } + + if (!servers.data.length) { + helpers.addResult(results, 0, 'No existing MySQL flexible servers found', location); + return rcb(); + } + + for (let server of servers.data) { + if (!server.id) continue; + + var diagnosticSettings = helpers.addSource(cache, source, + ['diagnosticSettings', 'listByMysqlFlexibleServer', location, server.id]); + + if (!diagnosticSettings || diagnosticSettings.err || !diagnosticSettings.data) { + helpers.addResult(results, 3, `Unable to query for MySQL flexible server diagnostic settings: ${helpers.addError(diagnosticSettings)}`, + location, server.id); + continue; + } + + var found = diagnosticSettings.data.find(ds => ds.logs && ds.logs.length); + + if (found) { + helpers.addResult(results, 0, 'MySQL flexible server has diagnostic logs enabled', location, server.id); + } else { + helpers.addResult(results, 2, 'MySQL flexible server does not have diagnostic logs enabled', location, server.id); + } + } + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js new file mode 100644 index 0000000000..eeb5d49495 --- /dev/null +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js @@ -0,0 +1,125 @@ +var expect = require('chai').expect; +var auth = require('./mysqlFlexibleServerLogsEnabled'); + +const servers = [ + { + "id": "/subscriptions/12345/resourceGroups/Default/providers/Microsoft.DBforMySQL/flexibleServers/test-server", + }, +]; + + +const diagnosticSettings = [ + { + id: '/subscriptions/234/myrg/providers/Microsoft.DBforPostgreSQL/servers/test/providers/microsoft.insights/diagnosticSettings/test-setting', + type: 'Microsoft.Insights/diagnosticSettings', + name: 'server-setting', + location: 'eastus', + kind: null, + tags: null, + eventHubName: null, + metrics: [], + logs: [ + { + "category": null, + "categoryGroup": "allLogs", + "enabled": true, + "retentionPolicy": { + "enabled": false, + "days": 0 + } + }, + { + "category": null, + "categoryGroup": "audit", + "enabled": false, + "retentionPolicy": { + "enabled": false, + "days": 0 + } + } + ], + logAnalyticsDestinationType: null + } +]; + +const createCache = (servers, ds) => { + const id = servers && servers.length ? servers[0].id : null; + return { + servers: { + listMysqlFlexibleServer: { + 'eastus': { + data: servers + } + } + }, + diagnosticSettings: { + listByMysqlFlexibleServer: { + 'eastus': { + [id]: { + data: ds + } + } + } + + }, + }; +}; + +describe('mysqlFlexibleServerLogsEnabled', function() { + describe('run', function() { + it('should give a passing result if no existing server found', function (done) { + const cache = createCache([], null); + auth.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 MySQL flexible servers found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if unable to query for server', function (done) { + const cache = createCache(null, ['error']); + auth.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 MySQL flexible servers: '); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + it('should give unknown result if unable to query for diagnostic settings', function(done) { + const cache = createCache([servers[0]], null); + auth.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 MySQL flexible server diagnostic settings'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if diagnostic logs enabled', function(done) { + const cache = createCache([servers[0]], [diagnosticSettings[0]]); + auth.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('MySQL flexible server has diagnostic logs enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if diagnostic logs not enabled', function(done) { + const cache = createCache([servers[0]], [[]]); + auth.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('MySQL flexible server does not have diagnostic logs enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); + From 9eb2fde5882792fb7576b9a2290acdff5c690071 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 04:06:00 +0500 Subject: [PATCH 19/73] F/Azure-mysqlServerManagedIdentity --- .../mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js index 66251a1c15..6daff9efa7 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js @@ -15,7 +15,7 @@ const createCache = (err, list) => { } }; -describe('mysqlFlexibleServersMinTls', function() { +describe('mysqlFlexibleServerManagedIdentity', function() { describe('run', function() { it('should PASS if no existing servers found', function(done) { const callback = (err, results) => { From 8976ee7328e563a8264078309bf70fb0748900e6 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Thu, 13 Jun 2024 04:07:13 +0500 Subject: [PATCH 20/73] F/Azure-mysqlFlexibleServerLatestVersion --- plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js index 7b42b881ff..b82a68c2b5 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js @@ -15,7 +15,7 @@ const createCache = (err, list) => { } }; -describe('mysqlFlexibleServersMinTls', function() { +describe('mysqlFlexibleServerVersion', function() { describe('run', function() { it('should PASS if no existing servers found', function(done) { const callback = (err, results) => { From 645afdc40e563762717ddbaf7150022468b14b0e Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Thu, 13 Jun 2024 14:59:35 +0500 Subject: [PATCH 21/73] update spec --- plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js b/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js index b5c4dd3f26..bc9d382ed3 100644 --- a/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js +++ b/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js @@ -74,7 +74,7 @@ describe('eventHubamespaceAutoInflate', function() { const callback = (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('Event Hubs namespace does not have auto-inflate feature enabled'); + expect(results[0].message).to.include('Event Hubs namespace does not have auto inflate feature enabled'); expect(results[0].region).to.equal('eastus'); done() }; @@ -87,7 +87,7 @@ describe('eventHubamespaceAutoInflate', function() { const callback = (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('Event Hubs namespace has auto-inflate feature enabled'); + expect(results[0].message).to.include('Event Hubs namespace has auto inflate feature enabled'); expect(results[0].region).to.equal('eastus'); done() }; From 2213b60700bf3440022cdc555812a466a2b259c5 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 00:46:35 +0500 Subject: [PATCH 22/73] plugin synapse workspace managed identity --- exports.js | 2 + helpers/azure/api.js | 5 ++ helpers/azure/locations.js | 3 +- helpers/azure/locations_gov.js | 3 +- .../azure/synapse/workspaceManagedIdentity.js | 52 +++++++++++ .../synapse/workspaceManagedIdentity.spec.js | 86 +++++++++++++++++++ 6 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 plugins/azure/synapse/workspaceManagedIdentity.js create mode 100644 plugins/azure/synapse/workspaceManagedIdentity.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..79389d80c6 100644 --- a/exports.js +++ b/exports.js @@ -1194,6 +1194,8 @@ module.exports = { 'workspaceManagedServicesCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedServicesCmk.js'), 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), + + 'workspaceManagedIdentity' : require(__dirname + '/plugins/azure/synapse/workspaceManagedIdentity.js'), }, github: { diff --git a/helpers/azure/api.js b/helpers/azure/api.js index 150b7491a2..d15abf88bf 100644 --- a/helpers/azure/api.js +++ b/helpers/azure/api.js @@ -564,6 +564,11 @@ var calls = { } }, + synapse: { + listWorkspaces: { + url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Synapse/workspaces?api-version=2021-06-01' + } + } }; diff --git a/helpers/azure/locations.js b/helpers/azure/locations.js index 280fb294ea..99a1fd13f7 100644 --- a/helpers/azure/locations.js +++ b/helpers/azure/locations.js @@ -134,5 +134,6 @@ module.exports = { databricks: locations, containerApps: locations, batchAccounts: locations, - machineLearning: locations + machineLearning: locations, + synapse: locations }; diff --git a/helpers/azure/locations_gov.js b/helpers/azure/locations_gov.js index 2e55d01403..5ab4f04fb6 100644 --- a/helpers/azure/locations_gov.js +++ b/helpers/azure/locations_gov.js @@ -84,5 +84,6 @@ module.exports = { publicIpAddresses: locations, computeGalleries: locations, databricks: locations, - containerApps: locations + containerApps: locations, + synapse: locations, }; diff --git a/plugins/azure/synapse/workspaceManagedIdentity.js b/plugins/azure/synapse/workspaceManagedIdentity.js new file mode 100644 index 0000000000..6921586daa --- /dev/null +++ b/plugins/azure/synapse/workspaceManagedIdentity.js @@ -0,0 +1,52 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'Synapse Workspace Managed Identity', + category: 'AI & ML', + domain: 'Machine Learning', + severity: 'Medium', + description: 'Ensure that Azure Synapse Analytics Workspace have managed identity enabled.', + more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', + recommended_action: 'Modify Synapse Workspace and enable managed identity.', + link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/synapse-service-identity', + apis: ['synapse:listWorkspaces'], + realtime_triggers: [], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.synapse, function(location, rcb) { + const workspaces = helpers.addSource(cache, source, + ['synapse', 'listWorkspaces', location]); + + if (!workspaces) return rcb(); + + + if (workspaces.err || !workspaces.data) { + helpers.addResult(results, 3, 'Unable to query Synapse workspaces: ' + helpers.addError(workspaces), location); + return rcb(); + } + + if (!workspaces.data.length) { + helpers.addResult(results, 0, 'No existing Synapse workspaces found', location); + return rcb(); + } + + for (let workspace of workspaces.data) { + if (workspace.identity && workspace.identity) { + helpers.addResult(results, 0, 'Synapse workspace has managed identity enabled', location, workspace.id); + } else { + helpers.addResult(results, 2, 'Synapse workspace does not have managed identity enabled', location, workspace.id); + } + } + + rcb(); + }, function() { + // Global checking goes here + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/synapse/workspaceManagedIdentity.spec.js b/plugins/azure/synapse/workspaceManagedIdentity.spec.js new file mode 100644 index 0000000000..760a2fc15e --- /dev/null +++ b/plugins/azure/synapse/workspaceManagedIdentity.spec.js @@ -0,0 +1,86 @@ +var expect = require('chai').expect; +var workspaceManagedIdentity = require('./workspaceManagedIdentity'); + +const workspaces = [ + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + identity: { + type: "SystemAssigned", + tenantId: "1234532134532134532", + principalId: "13123232223223323", + }, + }, + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + }, +]; + + +const createCache = (workspaces, err) => { + + return { + synapse: { + listWorkspaces: { + 'eastus': { + data: workspaces, + err: err + } + } + } + }; +}; + +describe('workspaceManagedIdentity', function () { + describe('run', function () { + + it('should give a passing result if no Synapse workspaces are found', function (done) { + const cache = createCache([], null); + workspaceManagedIdentity.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 Synapse workspaces found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if unable to query for Synapse workspaces', function (done) { + const cache = createCache(null, ['error']); + workspaceManagedIdentity.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 Synapse workspaces'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if workspace has managed identity', function (done) { + const cache = createCache([workspaces[0]], null); + workspaceManagedIdentity.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Synapse workspace has managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if workspace does not have managed identity', function (done) { + const cache = createCache([workspaces[1]], null); + workspaceManagedIdentity.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Synapse workspace does not have managed identity enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From d79739270d64a3978247b2229109c179f63370a1 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 00:59:50 +0500 Subject: [PATCH 23/73] plugin synapse workspace aad auth --- exports.js | 2 + helpers/azure/api.js | 5 ++ helpers/azure/locations.js | 3 +- helpers/azure/locations_gov.js | 3 +- .../azure/synapse/workspaceAADAuthEnabled.js | 52 ++++++++++++ .../synapse/workspaceAADAuthEnabled.spec.js | 82 +++++++++++++++++++ 6 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 plugins/azure/synapse/workspaceAADAuthEnabled.js create mode 100644 plugins/azure/synapse/workspaceAADAuthEnabled.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..7c0d015b90 100644 --- a/exports.js +++ b/exports.js @@ -1194,6 +1194,8 @@ module.exports = { 'workspaceManagedServicesCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedServicesCmk.js'), 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), + + 'workspaceAADAuthEnabled' : require(__dirname + '/plugins/azure/synapse/workspaceAADAuthEnabled.js'), }, github: { diff --git a/helpers/azure/api.js b/helpers/azure/api.js index 150b7491a2..d15abf88bf 100644 --- a/helpers/azure/api.js +++ b/helpers/azure/api.js @@ -564,6 +564,11 @@ var calls = { } }, + synapse: { + listWorkspaces: { + url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Synapse/workspaces?api-version=2021-06-01' + } + } }; diff --git a/helpers/azure/locations.js b/helpers/azure/locations.js index 280fb294ea..99a1fd13f7 100644 --- a/helpers/azure/locations.js +++ b/helpers/azure/locations.js @@ -134,5 +134,6 @@ module.exports = { databricks: locations, containerApps: locations, batchAccounts: locations, - machineLearning: locations + machineLearning: locations, + synapse: locations }; diff --git a/helpers/azure/locations_gov.js b/helpers/azure/locations_gov.js index 2e55d01403..34ea27dda3 100644 --- a/helpers/azure/locations_gov.js +++ b/helpers/azure/locations_gov.js @@ -84,5 +84,6 @@ module.exports = { publicIpAddresses: locations, computeGalleries: locations, databricks: locations, - containerApps: locations + containerApps: locations, + synapse: locations }; diff --git a/plugins/azure/synapse/workspaceAADAuthEnabled.js b/plugins/azure/synapse/workspaceAADAuthEnabled.js new file mode 100644 index 0000000000..09dfc97c60 --- /dev/null +++ b/plugins/azure/synapse/workspaceAADAuthEnabled.js @@ -0,0 +1,52 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'Synapse Workspace AAD Auth Enabled', + category: 'AI & ML', + domain: 'Machine Learning', + severity: 'Medium', + description: 'Ensure that Azure Synapse Analytics Workspace have AAD Auth enabled.', + more_info: 'Enabling Microsoft Entra ID (AAD) Authentication for your Synapse workspace enhances security by ensuring that only authenticated and authorized users can access your resources. This feature integrates seamlessly with AAD, providing robust access control and simplifying user management.', + recommended_action: 'Modify Synapse Workspace and enable microsoft entra id authentication.', + link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/sql/active-directory-authentication', + apis: ['synapse:listWorkspaces'], + realtime_triggers: [], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.synapse, function(location, rcb) { + const workspaces = helpers.addSource(cache, source, + ['synapse', 'listWorkspaces', location]); + + if (!workspaces) return rcb(); + + + if (workspaces.err || !workspaces.data) { + helpers.addResult(results, 3, 'Unable to query Synapse workspaces: ' + helpers.addError(workspaces), location); + return rcb(); + } + + if (!workspaces.data.length) { + helpers.addResult(results, 0, 'No existing Synapse workspaces found', location); + return rcb(); + } + + for (let workspace of workspaces.data) { + if (workspace.azureADOnlyAuthentication) { + helpers.addResult(results, 0, 'Synapse workspace has AAD auth enabled', location, workspace.id); + } else { + helpers.addResult(results, 2, 'Synapse workspace does not have AAD auth enabled', location, workspace.id); + } + } + + rcb(); + }, function() { + // Global checking goes here + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/synapse/workspaceAADAuthEnabled.spec.js b/plugins/azure/synapse/workspaceAADAuthEnabled.spec.js new file mode 100644 index 0000000000..c4978ac19a --- /dev/null +++ b/plugins/azure/synapse/workspaceAADAuthEnabled.spec.js @@ -0,0 +1,82 @@ +var expect = require('chai').expect; +var workspaceAADAuthEnabled = require('./workspaceAADAuthEnabled'); + +const workspaces = [ + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + azureADOnlyAuthentication: true + }, + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + }, +]; + + +const createCache = (workspaces, err) => { + + return { + synapse: { + listWorkspaces: { + 'eastus': { + data: workspaces, + err: err + } + } + } + }; +}; + +describe('workspaceAADAuthEnabled', function () { + describe('run', function () { + + it('should give a passing result if no Synapse workspaces are found', function (done) { + const cache = createCache([], null); + workspaceAADAuthEnabled.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 Synapse workspaces found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if unable to query for Synapse workspaces', function (done) { + const cache = createCache(null, ['error']); + workspaceAADAuthEnabled.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 Synapse workspaces'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if workspace has AAD auth enabled', function (done) { + const cache = createCache([workspaces[0]], null); + workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Synapse workspace has AAD auth enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if workspace does not have AAD auth', function (done) { + const cache = createCache([workspaces[1]], null); + workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Synapse workspace does not have AAD auth enabled'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From 1d51c7a2c2006c20dc52664514c21456a0d3f011 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 01:16:48 +0500 Subject: [PATCH 24/73] plugin synapse workspace private endpoints --- exports.js | 2 + helpers/azure/api.js | 5 + helpers/azure/locations.js | 3 +- helpers/azure/locations_gov.js | 3 +- .../azure/synapse/workspacePrivateEndpoint.js | 53 +++++++++++ .../synapse/workspacePrivateEndpoint.spec.js | 94 +++++++++++++++++++ 6 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 plugins/azure/synapse/workspacePrivateEndpoint.js create mode 100644 plugins/azure/synapse/workspacePrivateEndpoint.spec.js diff --git a/exports.js b/exports.js index 9ca097916d..fe6f7c8a2b 100644 --- a/exports.js +++ b/exports.js @@ -1194,6 +1194,8 @@ module.exports = { 'workspaceManagedServicesCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedServicesCmk.js'), 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), + + 'workspacePrivateEndpoint' : require(__dirname + '/plugins/azure/synapse/workspacePrivateEndpoint.js'), }, github: { diff --git a/helpers/azure/api.js b/helpers/azure/api.js index 150b7491a2..d15abf88bf 100644 --- a/helpers/azure/api.js +++ b/helpers/azure/api.js @@ -564,6 +564,11 @@ var calls = { } }, + synapse: { + listWorkspaces: { + url: 'https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Synapse/workspaces?api-version=2021-06-01' + } + } }; diff --git a/helpers/azure/locations.js b/helpers/azure/locations.js index 280fb294ea..99a1fd13f7 100644 --- a/helpers/azure/locations.js +++ b/helpers/azure/locations.js @@ -134,5 +134,6 @@ module.exports = { databricks: locations, containerApps: locations, batchAccounts: locations, - machineLearning: locations + machineLearning: locations, + synapse: locations }; diff --git a/helpers/azure/locations_gov.js b/helpers/azure/locations_gov.js index 2e55d01403..34ea27dda3 100644 --- a/helpers/azure/locations_gov.js +++ b/helpers/azure/locations_gov.js @@ -84,5 +84,6 @@ module.exports = { publicIpAddresses: locations, computeGalleries: locations, databricks: locations, - containerApps: locations + containerApps: locations, + synapse: locations }; diff --git a/plugins/azure/synapse/workspacePrivateEndpoint.js b/plugins/azure/synapse/workspacePrivateEndpoint.js new file mode 100644 index 0000000000..4ee28b045d --- /dev/null +++ b/plugins/azure/synapse/workspacePrivateEndpoint.js @@ -0,0 +1,53 @@ +var async = require('async'); +var helpers = require('../../../helpers/azure'); + +module.exports = { + title: 'Synapse Workspace Private Endpoints', + category: 'AI & ML', + domain: 'Machine Learning', + severity: 'Medium', + description: 'Ensure that Azure Synapse Analytics Workspace are accessible only through private endpoints.', + more_info: 'Azure Private Endpoint is a network interface that connects you privately and securely to a service powered by Azure Private Link. Private Endpoint uses a private IP address from your VNet, effectively bringing the service such as Azure Storage Accounts into your VNet.', + recommended_action: 'Modify Synapse Workspace and configure private endpoints.', + link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links', + apis: ['synapse:listWorkspaces'], + realtime_triggers: [], + + run: function(cache, settings, callback) { + const results = []; + const source = {}; + const locations = helpers.locations(settings.govcloud); + + async.each(locations.synapse, function(location, rcb) { + const workspaces = helpers.addSource(cache, source, + ['synapse', 'listWorkspaces', location]); + + if (!workspaces) return rcb(); + + + if (workspaces.err || !workspaces.data) { + helpers.addResult(results, 3, 'Unable to query Synapse workspaces: ' + helpers.addError(workspaces), location); + return rcb(); + } + + if (!workspaces.data.length) { + helpers.addResult(results, 0, 'No existing Synapse workspaces found', location); + return rcb(); + } + + for (let workspace of workspaces.data) { + if (workspace.privateEndpointConnections && + workspace.privateEndpointConnections.length) { + helpers.addResult(results, 0, 'Private endpoints are configured for the Synapse workspace', location, workspace.id); + } else { + helpers.addResult(results, 2, 'Private endpoints are not configured for the Synapse workspace', location, workspace.id); + } + } + + rcb(); + }, function() { + // Global checking goes here + callback(null, results, source); + }); + } +}; \ No newline at end of file diff --git a/plugins/azure/synapse/workspacePrivateEndpoint.spec.js b/plugins/azure/synapse/workspacePrivateEndpoint.spec.js new file mode 100644 index 0000000000..55094afe1d --- /dev/null +++ b/plugins/azure/synapse/workspacePrivateEndpoint.spec.js @@ -0,0 +1,94 @@ +var expect = require('chai').expect; +var workspacePrivateEndpoint = require('./workspacePrivateEndpoint'); + +const workspaces = [ + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + azureADOnlyAuthentication: true, + privateEndpointConnections: [{ + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test/privateEndpointConnections/test-endpoint-synapse-123", + properties: { + privateEndpoint: { + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Network/privateEndpoints/test-endpoint-synapse", + }, + privateLinkServiceConnectionState: { + status: "Approved", + }, + }, + }], + }, + { + type: "Microsoft.Synapse/workspaces", + id: "/subscriptions/123/resourceGroups/rsgrp/providers/Microsoft.Synapse/workspaces/test", + location: "eastus", + name: "test", + privateEndpointConnections: [] + }, +]; + + +const createCache = (workspaces, err) => { + + return { + synapse: { + listWorkspaces: { + 'eastus': { + data: workspaces, + err: err + } + } + } + }; +}; + +describe('workspacePrivateEndpoint', function () { + describe('run', function () { + + it('should give a passing result if no Synapse workspaces are found', function (done) { + const cache = createCache([], null); + workspacePrivateEndpoint.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 Synapse workspaces found'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give unknown result if unable to query for Synapse workspaces', function (done) { + const cache = createCache(null, ['error']); + workspacePrivateEndpoint.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 Synapse workspaces'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give passing result if workspace has Private endpoints configured ', function (done) { + const cache = createCache([workspaces[0]], null); + workspacePrivateEndpoint.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(0); + expect(results[0].message).to.include('Private endpoints are configured for the Synapse workspace'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + + it('should give failing result if workspace does not have Private endpoints configured', function (done) { + const cache = createCache([workspaces[1]], null); + workspacePrivateEndpoint.run(cache, {}, (err, results) => { + expect(results.length).to.equal(1); + expect(results[0].status).to.equal(2); + expect(results[0].message).to.include('Private endpoints are not configured for the Synapse workspace'); + expect(results[0].region).to.equal('eastus'); + done(); + }); + }); + }); +}); \ No newline at end of file From 6a5a2c8ba2fae24e105359c85da377d85bba98c8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 14:23:48 +0500 Subject: [PATCH 25/73] add triggers --- plugins/azure/synapse/workspaceAADAuthEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/synapse/workspaceAADAuthEnabled.js b/plugins/azure/synapse/workspaceAADAuthEnabled.js index 09dfc97c60..c7a5454713 100644 --- a/plugins/azure/synapse/workspaceAADAuthEnabled.js +++ b/plugins/azure/synapse/workspaceAADAuthEnabled.js @@ -11,7 +11,7 @@ module.exports = { recommended_action: 'Modify Synapse Workspace and enable microsoft entra id authentication.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/sql/active-directory-authentication', apis: ['synapse:listWorkspaces'], - realtime_triggers: [], + realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], run: function(cache, settings, callback) { const results = []; From 454b5ba206517bf9c705e7b49179414932d6d07c Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 14:26:40 +0500 Subject: [PATCH 26/73] add triggers --- plugins/azure/synapse/workspaceManagedIdentity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/synapse/workspaceManagedIdentity.js b/plugins/azure/synapse/workspaceManagedIdentity.js index 6921586daa..028748792c 100644 --- a/plugins/azure/synapse/workspaceManagedIdentity.js +++ b/plugins/azure/synapse/workspaceManagedIdentity.js @@ -11,7 +11,7 @@ module.exports = { recommended_action: 'Modify Synapse Workspace and enable managed identity.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/synapse-service-identity', apis: ['synapse:listWorkspaces'], - realtime_triggers: [], + realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], run: function(cache, settings, callback) { const results = []; From 324b786465b35d25ae571133f6de5b8684116e51 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 14:27:33 +0500 Subject: [PATCH 27/73] add triggers --- plugins/azure/synapse/workspacePrivateEndpoint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/synapse/workspacePrivateEndpoint.js b/plugins/azure/synapse/workspacePrivateEndpoint.js index 4ee28b045d..ff3805a8bf 100644 --- a/plugins/azure/synapse/workspacePrivateEndpoint.js +++ b/plugins/azure/synapse/workspacePrivateEndpoint.js @@ -11,7 +11,7 @@ module.exports = { recommended_action: 'Modify Synapse Workspace and configure private endpoints.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links', apis: ['synapse:listWorkspaces'], - realtime_triggers: [], + realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], run: function(cache, settings, callback) { const results = []; From 9942758fd0350dd7966c793e18626c7e442a05b7 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 14:32:03 +0500 Subject: [PATCH 28/73] update --- plugins/azure/eventhub/eventHubamespaceAutoInflate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js index 609b230f56..a5e1431328 100644 --- a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js +++ b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js @@ -7,7 +7,7 @@ module.exports = { category: 'Event Hubs', domain: 'Content Delivery', severity: 'Low', - description: 'Ensure that Event Hubs namespace have Auto Inflate feature enabled', + description: 'Ensure that Event Hubs namespace have Auto Inflate feature enabled.', more_info: 'Enabling Auto-inflate for your Azure Event Hubs namespace ensures seamless scaling by automatically adjusting the number of throughput units (TUs) based on workload demands. This feature helps prevent throttling issues by scaling up as needed, providing efficient and reliable data handling without manual intervention.', recommended_action: 'Modify Event Hub namespace and enable auto-inflate feature.', link: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate', From ab268ca215738e8dc371b4f5d34c9c7b6d2092b8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Fri, 14 Jun 2024 14:33:27 +0500 Subject: [PATCH 29/73] update --- plugins/aws/documentDB/docdbClusterProfilerEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js index 0ed6ff5547..fc728dea23 100644 --- a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js +++ b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js @@ -6,7 +6,7 @@ module.exports = { category: 'DocumentDB', domain: 'Databases', severity: 'Medium', - description: 'Ensure that Amazon DocumentDB clusters have Profiler feature enabled.', + description: 'Ensure that Amazon DocumentDB clusters have profiler feature enabled.', more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps you to monitor and log slow database operations. This makes it easier to identify and fix performance issues by analyzing detailed logs in Amazon CloudWatch.', recommended_action: 'Modify DocumentDb cluster and enable profiler feature.', link: 'https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html', From 7fac7d31067d26ab3ddd28b4e62867c83d254a59 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 15:08:42 +0500 Subject: [PATCH 30/73] F/Azure-mysqlServerManagedIdentity --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 253701c18f..996d56a9d1 100644 --- a/exports.js +++ b/exports.js @@ -855,7 +855,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), - 'mysqlServerManagedIdentity' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerManagedIdentity.js'), + 'mysqlServerFlexibleManagedIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqlServerFlexibleManagedIdentity.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), From b3a0e31ce26b058f1ab079bcc177d660be10828e Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 15:11:08 +0500 Subject: [PATCH 31/73] F/Azure-mysqlServerManagedIdentity --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 996d56a9d1..50a0b40970 100644 --- a/exports.js +++ b/exports.js @@ -855,7 +855,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), - 'mysqlServerFlexibleManagedIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqlServerFlexibleManagedIdentity.js'), + 'mysqFlexibleServerManagedIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqFlexibleServerManagedIdentity.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), From fe6aa4c9b250264c56199c62d9173aff58e24779 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:49:34 +0500 Subject: [PATCH 32/73] Update plugins/aws/healthlake/dataStoreHasTags.js --- plugins/aws/healthlake/dataStoreHasTags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/healthlake/dataStoreHasTags.js b/plugins/aws/healthlake/dataStoreHasTags.js index 4ba8b2bdd5..80c7828fe8 100644 --- a/plugins/aws/healthlake/dataStoreHasTags.js +++ b/plugins/aws/healthlake/dataStoreHasTags.js @@ -6,7 +6,7 @@ module.exports = { category: 'AI & ML', domain: 'Content Delivery', severity: 'Low', - description: 'Ensure that HealthLake data stores have tags associated.', + description: 'Ensure that HealthLake Data Store has tags associated.', more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', recommended_action: 'Modify HealthLake data store and add tags.', link: 'https://docs.aws.amazon.com/healthlake/latest/devguide/add-a-tag.html', From e9a7b9623b85b08aad57ea8fff0bac4f10589a03 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 15:56:38 +0500 Subject: [PATCH 33/73] F/Azure-mysqlServerManagedIdentity --- exports.js | 2 +- ...eServerManagedIdentity.js => mysqlFlexibleServerIdentity.js} | 0 ...agedIdentity.spec.js => mysqlFlexibleServerIdentity.spec.js} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename plugins/azure/mysqlserver/{mysqlFlexibleServerManagedIdentity.js => mysqlFlexibleServerIdentity.js} (100%) rename plugins/azure/mysqlserver/{mysqlFlexibleServerManagedIdentity.spec.js => mysqlFlexibleServerIdentity.spec.js} (98%) diff --git a/exports.js b/exports.js index 50a0b40970..28ace3f747 100644 --- a/exports.js +++ b/exports.js @@ -855,7 +855,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), - 'mysqFlexibleServerManagedIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqFlexibleServerManagedIdentity.js'), + 'mysqlFlexibleServerIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js b/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js similarity index 100% rename from plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.js rename to plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.spec.js similarity index 98% rename from plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js rename to plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.spec.js index 6daff9efa7..fb6a5adf23 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerManagedIdentity.spec.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.spec.js @@ -1,6 +1,6 @@ var assert = require('assert'); var expect = require('chai').expect; -var auth = require('./mysqlFlexibleServerManagedIdentity'); +var auth = require('./mysqlFlexibleServerIdentity'); const createCache = (err, list) => { return { From bd905b732c2e4e0f1b11e84b50759e4721fb3093 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:02:16 +0500 Subject: [PATCH 34/73] Update plugins/azure/batchAccounts/batchAccountsPublicAccess.js --- plugins/azure/batchAccounts/batchAccountsPublicAccess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/batchAccounts/batchAccountsPublicAccess.js b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js index 76e15efddb..892df4a591 100644 --- a/plugins/azure/batchAccounts/batchAccountsPublicAccess.js +++ b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js @@ -6,7 +6,7 @@ module.exports = { category: 'Batch', domain: 'Compute', severity: 'Medium', - description: 'Ensures that Batch account are not publicly accessible.', + description: 'Ensures that Batch accounts are not publicly accessible.', more_info: 'Disabling public access for your Azure Batch Account enhances security by restricting unauthorized access to your batch resources. This setting ensures that only trusted, internal sources can interact with your batch services, protecting your data and processes from potential external threats.', recommended_action: 'Modify Batch Account and disable public access.', link: 'https://learn.microsoft.com/en-us/azure/batch/public-network-access', From ecd1491ee11142a695c8ce8dd3b907e7a59001ce Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:30:58 +0500 Subject: [PATCH 35/73] Update plugins/azure/batchAccounts/batchAccountsHasTags.js --- plugins/azure/batchAccounts/batchAccountsHasTags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/batchAccounts/batchAccountsHasTags.js b/plugins/azure/batchAccounts/batchAccountsHasTags.js index 6651dc08a0..14339bf9d0 100644 --- a/plugins/azure/batchAccounts/batchAccountsHasTags.js +++ b/plugins/azure/batchAccounts/batchAccountsHasTags.js @@ -6,7 +6,7 @@ module.exports = { category: 'Batch', domain: 'Compute', severity: 'Low', - description: 'Ensures that Batch account have tags associated.', + description: 'Ensures that Batch accounts have tags associated.', more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', recommended_action: 'Modify Batch Account and add tags.', link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal', From de86d31fdc148acbb47288b1db106255d6c199d9 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:31:26 +0500 Subject: [PATCH 36/73] Update plugins/azure/batchAccounts/batchAccountsHasTags.js --- plugins/azure/batchAccounts/batchAccountsHasTags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/batchAccounts/batchAccountsHasTags.js b/plugins/azure/batchAccounts/batchAccountsHasTags.js index 14339bf9d0..2d073d80ef 100644 --- a/plugins/azure/batchAccounts/batchAccountsHasTags.js +++ b/plugins/azure/batchAccounts/batchAccountsHasTags.js @@ -10,7 +10,7 @@ module.exports = { more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', recommended_action: 'Modify Batch Account and add tags.', link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal', - apis: ['batchAccounts:list','diagnosticSettings:listByBatchAccounts'], + apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], run: function(cache, settings, callback) { From 9480e002887522f570efcecaebe1411d82ea4fae Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 23:05:45 +0500 Subject: [PATCH 37/73] F/Azure-mysqlFlexibleServerLogs --- exports.js | 2 +- ...erLogsEnabled.js => mysqlFlexibleServerDignosticLogs.js} | 6 +++--- ...led.spec.js => mysqlFlexibleServerDignosticLogs.spec.js} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename plugins/azure/mysqlserver/{mysqlFlexibleServerLogsEnabled.js => mysqlFlexibleServerDignosticLogs.js} (94%) rename plugins/azure/mysqlserver/{mysqlFlexibleServerLogsEnabled.spec.js => mysqlFlexibleServerDignosticLogs.spec.js} (98%) diff --git a/exports.js b/exports.js index 80c941a46e..17214262e8 100644 --- a/exports.js +++ b/exports.js @@ -852,10 +852,10 @@ module.exports = { 'resourceAllowedLocations' : require(__dirname + '/plugins/azure/policyservice/resourceAllowedLocations.js'), 'resourceLocationMatch' : require(__dirname + '/plugins/azure/policyservice/resourceLocationMatch.js'), - 'mysqlFlexibleServerLogsEnabled': require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js'), 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), + 'mysqlFlexibleServerDignosticLogs': require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js similarity index 94% rename from plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js rename to plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js index 637bc54e6c..0819eaadf3 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js @@ -2,14 +2,14 @@ const async = require('async'); const helpers = require('../../../helpers/azure'); module.exports = { - title: 'MySQL Flexible Server Logging Enabled', + title: 'MySQL Flexible Server Diagnostic Logs', category: 'MySQL Server', domain: 'Databases', severity: 'Medium', - description: 'Ensures diagnostic logging is enabled for MySQL Flexible server.', + description: 'Ensures that diagnostic logging is enabled for MySQL Flexible server.', more_info: 'Enabling diagnostic logging for Azure Database for MySQL Flexible servers helps with performance monitoring, troubleshooting, and security optimization.', recommended_action: 'Enable diagnostic logging for all MySQL Flexible Servers.', - link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/tutorial-configure-audit', + link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concepts-monitoring', apis: ['servers:listMysqlFlexibleServer', 'diagnosticSettings:listByMysqlFlexibleServer'], realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete', 'microsoftinsights:diagnosticsettings:write','microsoftinsights:diagnosticsettings:delete'], diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.spec.js similarity index 98% rename from plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js rename to plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.spec.js index eeb5d49495..c1e8dbc734 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerLogsEnabled.spec.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.spec.js @@ -1,5 +1,5 @@ var expect = require('chai').expect; -var auth = require('./mysqlFlexibleServerLogsEnabled'); +var auth = require('./mysqlFlexibleServerDignosticLogs'); const servers = [ { From 785001617add664f3bdb28d89b7375b6f63e8924 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 23:13:59 +0500 Subject: [PATCH 38/73] F/Azure-mysqlFlexibleServerLatestVersion --- plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js index 2c17595995..6fe1b56bbe 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js @@ -7,7 +7,7 @@ module.exports = { domain: 'Databases', severity: 'Medium', description: 'Ensures that MySQL Flexible Servers are using the latest server version.', - more_info: 'Using the latest version of Upgrade the version of PostgreSQL flexible server to the latest available version. will give access to new software features, resolve reported bugs through security patches, and improve compatibility with other applications and services', + more_info: 'Using the latest version of Upgrade the version of MySQL flexible server to the latest available version will give access to new software features, resolve reported bugs through security patches, and improve compatibility with other applications and services.', recommended_action: 'Ensure MySQL Flexible Servers are using the latest server version.', link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/how-to-upgrade', apis: ['servers:listMysqlFlexibleServer'], @@ -36,7 +36,7 @@ module.exports = { } for (var flexibleServer of servers.data) { - if (!flexibleServer.id) return; + if (!flexibleServer.id || !flexibleServer.version) continue; let version = parseFloat(flexibleServer.version); From d984f78dbacceb663e2395f44b27097e7d662449 Mon Sep 17 00:00:00 2001 From: fatima99s Date: Fri, 14 Jun 2024 23:18:23 +0500 Subject: [PATCH 39/73] F/AWS-GuarddutyLambdaProtection --- plugins/aws/guardduty/lambdaProtectionEnabled.js | 8 ++++---- plugins/aws/guardduty/lambdaProtectionEnabled.spec.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/aws/guardduty/lambdaProtectionEnabled.js b/plugins/aws/guardduty/lambdaProtectionEnabled.js index 0292fb5239..03a57d92b9 100644 --- a/plugins/aws/guardduty/lambdaProtectionEnabled.js +++ b/plugins/aws/guardduty/lambdaProtectionEnabled.js @@ -7,7 +7,7 @@ module.exports = { domain: 'Management and Governance', severity: 'Medium', description: 'Ensures GuardDuty protection is enabled for Lambda functions.' , - more_info: 'Lambda Protection helps detect potential security threats in your Lambda functions by monitoring network activity logs and generating findings for suspicious traffic.', + more_info: 'Enabling GuardDuty Lambda Protection helps detect potential security threats offering enhanced security by monitoring network activity logs and generating findings for suspicious activities or security issues.', recommended_action: 'Enable GuardDuty Lambda protection for all AWS accounts.', link: 'https://docs.aws.amazon.com/guardduty/latest/ug/lambda-protection.html', apis: ['GuardDuty:listDetectors', 'GuardDuty:getDetector', 'STS:getCallerIdentity'], @@ -45,7 +45,7 @@ module.exports = { if (!getDetector) return; if (getDetector.err || !getDetector.data) { - helpers.addResult(results, 3, 'Unable to get GuardDuty detector: ' + helpers.addError(getDetector),region); + helpers.addResult(results, 3, 'Unable to get GuardDuty detector: ' + helpers.addError(getDetector),region, detectorId); return; } @@ -54,9 +54,9 @@ module.exports = { var lambdaLoginEventsFeature = (detector.Features && detector.Features.find(feature => feature.Name === 'LAMBDA_NETWORK_LOGS' && feature.Status === 'ENABLED')) ? true : false; if (lambdaLoginEventsFeature) { - helpers.addResult(results, 0, 'GuardDuty lambda protection is enabled' , region, resource); + helpers.addResult(results, 0, 'GuardDuty Lambda protection is enabled' , region, resource); } else { - helpers.addResult(results, 2, 'GuardDuty lambda protection is disabled ' , region, resource); + helpers.addResult(results, 2, 'GuardDuty Lambda protection is disabled ' , region, resource); } }); diff --git a/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js b/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js index c81f9516d8..f35b1e651b 100644 --- a/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js +++ b/plugins/aws/guardduty/lambdaProtectionEnabled.spec.js @@ -157,7 +157,7 @@ describe('lambdaProtectionEnabled', function () { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); expect(results[0].region).to.equal('us-east-1'); - expect(results[0].message).to.include('GuardDuty lambda protection is disabled'); + expect(results[0].message).to.include('GuardDuty Lambda protection is disabled'); done(); }); }); @@ -168,7 +168,7 @@ describe('lambdaProtectionEnabled', function () { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); expect(results[0].region).to.equal('us-east-1'); - expect(results[0].message).to.include('GuardDuty lambda protection is enabled'); + expect(results[0].message).to.include('GuardDuty Lambda protection is enabled'); done(); }); }); From 5d81e0b4315e37935b03d70435d14bcc6290bf2e Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 15:51:49 +0500 Subject: [PATCH 40/73] Apply suggestions from code review --- plugins/aws/apigateway/apigatewayRequestValidation.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/aws/apigateway/apigatewayRequestValidation.js b/plugins/aws/apigateway/apigatewayRequestValidation.js index 608c45310d..4c56b20c3a 100644 --- a/plugins/aws/apigateway/apigatewayRequestValidation.js +++ b/plugins/aws/apigateway/apigatewayRequestValidation.js @@ -2,16 +2,16 @@ var async = require('async'); var helpers = require('../../../helpers/aws'); module.exports = { - title: 'API Gateway Request validation', + title: 'API Gateway Request Validation', category: 'API Gateway', domain: 'Availability', severity: 'Medium', description: 'Ensures that Amazon API Gateway method has request validation enabled.', - more_info: 'Enabling request validation for API Gateway allows to perform basic validation of an API request before proceeding with the integration request. When request validation fails, API Gateway immediately fails the request reduceing unnecessary calls to the backend.', - recommended_action: 'Modify API Gateway configuration and ensure that appropriate request validators are set up for each API.', + more_info: 'Enabling request validation for API Gateway allows to perform basic validation of an API request before proceeding with the integration request and publishes the validation results in CloudWatch Logs. When request validation fails, API Gateway immediately fails the request reducing unnecessary calls to the backend.', + recommended_action: 'Modify API Gateway configuration and ensure that appropriate request validators are set for each API.', link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-method-request-validation.html', apis: ['APIGateway:getRestApis', 'APIGateway:getRequestValidators'], - realtime_triggers: ['apigateway:CreateRestApi','apigateway:DeleteRestApi','apigateway:ImportRestApi','apigateway:CreateAuthorizer','apigateway:DeleteAuthorizer'], + realtime_triggers: ['apigateway:CreateRestApi','apigateway:DeleteRestApi','apigateway:ImportRestApi','apigateway:CreateRequestValidator','apigateway:UpdateRequestValidator','apigateway:DeleteRequestValidator'], run: function(cache, settings, callback) { var results = []; @@ -54,7 +54,7 @@ module.exports = { if (!getRequestValidators.data.items.length) { helpers.addResult(results, 2, 'No request validators found for API Gateway Rest API', - region, apiArn ); + region, apiArn); } else { helpers.addResult(results, 0, 'Request validators found for API Gateway Rest API', From 0febeca306f2b78f3853721c9ea376d57ff9a553 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 17:20:07 +0500 Subject: [PATCH 41/73] Update plugins/aws/guardduty/lambdaProtectionEnabled.js --- plugins/aws/guardduty/lambdaProtectionEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/guardduty/lambdaProtectionEnabled.js b/plugins/aws/guardduty/lambdaProtectionEnabled.js index 03a57d92b9..7e960bc4c8 100644 --- a/plugins/aws/guardduty/lambdaProtectionEnabled.js +++ b/plugins/aws/guardduty/lambdaProtectionEnabled.js @@ -7,7 +7,7 @@ module.exports = { domain: 'Management and Governance', severity: 'Medium', description: 'Ensures GuardDuty protection is enabled for Lambda functions.' , - more_info: 'Enabling GuardDuty Lambda Protection helps detect potential security threats offering enhanced security by monitoring network activity logs and generating findings for suspicious activities or security issues.', + more_info: 'Enabling GuardDuty Lambda Protection helps detect potential security threats offering enhanced security by monitoring network activity logs and generating findings for suspicious activities and security issues.', recommended_action: 'Enable GuardDuty Lambda protection for all AWS accounts.', link: 'https://docs.aws.amazon.com/guardduty/latest/ug/lambda-protection.html', apis: ['GuardDuty:listDetectors', 'GuardDuty:getDetector', 'STS:getCallerIdentity'], From d59999058c13e217c64b4273adcb2d040b281c39 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 17:34:04 +0500 Subject: [PATCH 42/73] Fixed-Requested-changes --- .../azure/mysqlserver/mysqlFlexibleServerVersion.js | 13 ++++++------- .../mysqlserver/mysqlFlexibleServerVersion.spec.js | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js index 6fe1b56bbe..749ec2d833 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.js @@ -6,7 +6,7 @@ module.exports = { category: 'MySQL Server', domain: 'Databases', severity: 'Medium', - description: 'Ensures that MySQL Flexible Servers are using the latest server version.', + description: 'Ensures that MySQL flexible servers are using the latest server version.', more_info: 'Using the latest version of Upgrade the version of MySQL flexible server to the latest available version will give access to new software features, resolve reported bugs through security patches, and improve compatibility with other applications and services.', recommended_action: 'Ensure MySQL Flexible Servers are using the latest server version.', link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/how-to-upgrade', @@ -17,6 +17,7 @@ module.exports = { const results = []; const source = {}; const locations = helpers.locations(settings.govcloud); + const latestServerVersion = 8.0; async.each(locations.servers, (location, rcb) => { const servers = helpers.addSource(cache, source, @@ -36,16 +37,14 @@ module.exports = { } for (var flexibleServer of servers.data) { - if (!flexibleServer.id || !flexibleServer.version) continue; - - let version = parseFloat(flexibleServer.version); + if (!flexibleServer.id) continue; - if (version && version >= 8.0) { + if (flexibleServer.version && parseFloat(flexibleServer.version) >= latestServerVersion) { helpers.addResult(results, 0, - 'MySQL flexible server has latest server version', location, flexibleServer.id); + `MySQL flexible server has latest server version: ${flexibleServer.version}`, location, flexibleServer.id); } else { helpers.addResult(results, 2, - 'MySQL flexible server does not have latest server version', location, flexibleServer.id); + `MySQL flexible server does not have latest server version: ${latestServerVersion}`, location, flexibleServer.id); } } rcb(); diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js index b82a68c2b5..9ac967507b 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerVersion.spec.js @@ -39,7 +39,7 @@ describe('mysqlFlexibleServerVersion', function() { const callback = (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('MySQL flexible server does not have latest server version'); + expect(results[0].message).to.include('MySQL flexible server does not have latest server version: 8'); expect(results[0].region).to.equal('eastus'); done() }; @@ -62,7 +62,7 @@ describe('mysqlFlexibleServerVersion', function() { const callback = (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('MySQL flexible server has latest server version'); + expect(results[0].message).to.include('MySQL flexible server has latest server version: 8'); expect(results[0].region).to.equal('eastus'); done() }; From 54de1fbf7d632fdaf675f8037010cf631c5801e9 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 17:43:36 +0500 Subject: [PATCH 43/73] M/Requested-changes --- plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js b/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js index 42d92dc34e..a770cf0477 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js @@ -6,9 +6,9 @@ module.exports = { category: 'MySQL Server', domain: 'Databases', severity: 'Medium', - description: 'Ensures that MySQL Flexible Servers have managed identity enabled.', + description: 'Ensures that MySQL flexible servers have managed identity enabled.', more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', - recommended_action: 'Modify MySQL Flexible Server add managed identity.', + recommended_action: 'Modify MySQL flexible server add managed identity.', link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/how-to-azure-ad', apis: ['servers:listMysqlFlexibleServer'], realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete'], From 7581b1a64539a64905ae287c8fdd602c5977d0ee Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 17:44:55 +0500 Subject: [PATCH 44/73] M/Requested-changes --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 28ace3f747..db019a39f8 100644 --- a/exports.js +++ b/exports.js @@ -855,7 +855,7 @@ module.exports = { 'enforceMySQLSSLConnection' : require(__dirname + '/plugins/azure/mysqlserver/enforceMySQLSSLConnection.js'), 'mysqlFlexibleServersMinTls' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServersMinTls.js'), 'mysqlServerHasTags' : require(__dirname + '/plugins/azure/mysqlserver/mysqlServerHasTags.js'), - 'mysqlFlexibleServerIdentity': require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js'), + 'mysqlFlexibleServerIdentity' : require(__dirname + '/plugins/azure/mysqlserver/mysqlFlexibleServerIdentity.js'), 'logRetentionDays' : require(__dirname + '/plugins/azure/postgresqlserver/logRetentionDays.js'), 'connectionThrottlingEnabled' : require(__dirname + '/plugins/azure/postgresqlserver/connectionThrottlingEnabled.js'), From d74f7ec75d5cd6d0ca8edfd357aeb6871fe94005 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 17:51:34 +0500 Subject: [PATCH 45/73] M/Requested-changes --- .../azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js index 0819eaadf3..16f911b141 100644 --- a/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js +++ b/plugins/azure/mysqlserver/mysqlFlexibleServerDignosticLogs.js @@ -6,12 +6,12 @@ module.exports = { category: 'MySQL Server', domain: 'Databases', severity: 'Medium', - description: 'Ensures that diagnostic logging is enabled for MySQL Flexible server.', + description: 'Ensures that MySQL flexible server has diagnostic logs enabled.', more_info: 'Enabling diagnostic logging for Azure Database for MySQL Flexible servers helps with performance monitoring, troubleshooting, and security optimization.', - recommended_action: 'Enable diagnostic logging for all MySQL Flexible Servers.', + recommended_action: 'Enable diagnostic logging for all MySQL flexible servers.', link: 'https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concepts-monitoring', apis: ['servers:listMysqlFlexibleServer', 'diagnosticSettings:listByMysqlFlexibleServer'], - realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete', 'microsoftinsights:diagnosticsettings:write','microsoftinsights:diagnosticsettings:delete'], + realtime_triggers: ['microsoftdbformysql:flexibleservers:write','microsoftdbformysql:flexibleservers:delete','microsoftinsights:diagnosticsettings:write','microsoftinsights:diagnosticsettings:delete'], run: function(cache, settings, callback) { const results = []; From 8d4e68ed36a600cc88bcbd26eb1501aae5efefef Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 18:01:40 +0500 Subject: [PATCH 46/73] Apply suggestions from code review --- plugins/azure/batchAccounts/batchAccountsHasTags.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/azure/batchAccounts/batchAccountsHasTags.js b/plugins/azure/batchAccounts/batchAccountsHasTags.js index 2d073d80ef..0ab99cb4dd 100644 --- a/plugins/azure/batchAccounts/batchAccountsHasTags.js +++ b/plugins/azure/batchAccounts/batchAccountsHasTags.js @@ -6,9 +6,9 @@ module.exports = { category: 'Batch', domain: 'Compute', severity: 'Low', - description: 'Ensures that Batch accounts have tags associated.', + description: 'Ensures that Azure Batch accounts have tags associated.', more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', - recommended_action: 'Modify Batch Account and add tags.', + recommended_action: 'Modify Batch account and add tags.', link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources-portal', apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], @@ -19,7 +19,6 @@ module.exports = { var locations = helpers.locations(settings.govcloud); async.each(locations.batchAccounts, function(location, rcb){ - var batchAccounts = helpers.addSource(cache, source, ['batchAccounts', 'list', location]); From d26e8ef8ae08e3dd7742b872c9a2aa1d37b7c8da Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 18:02:34 +0500 Subject: [PATCH 47/73] Update plugins/azure/eventhub/eventHubamespaceAutoInflate.js --- plugins/azure/eventhub/eventHubamespaceAutoInflate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js index a5e1431328..aa34facf77 100644 --- a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js +++ b/plugins/azure/eventhub/eventHubamespaceAutoInflate.js @@ -7,7 +7,7 @@ module.exports = { category: 'Event Hubs', domain: 'Content Delivery', severity: 'Low', - description: 'Ensure that Event Hubs namespace have Auto Inflate feature enabled.', + description: 'Ensure that Event Hubs namespaces have Auto Inflate feature enabled.', more_info: 'Enabling Auto-inflate for your Azure Event Hubs namespace ensures seamless scaling by automatically adjusting the number of throughput units (TUs) based on workload demands. This feature helps prevent throttling issues by scaling up as needed, providing efficient and reliable data handling without manual intervention.', recommended_action: 'Modify Event Hub namespace and enable auto-inflate feature.', link: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate', From 36122b0acd034b70a5a34f088480e75851aa06d8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 18:30:15 +0500 Subject: [PATCH 48/73] M/Requested-Changes --- ...tHubamespaceAutoInflate.js => eventHubNamespaceAutoInflate.js} | 0 ...ceAutoInflate.spec.js => eventHubNamespaceAutoInflate.spec.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename plugins/azure/eventhub/{eventHubamespaceAutoInflate.js => eventHubNamespaceAutoInflate.js} (100%) rename plugins/azure/eventhub/{eventHubamespaceAutoInflate.spec.js => eventHubNamespaceAutoInflate.spec.js} (100%) diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.js b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js similarity index 100% rename from plugins/azure/eventhub/eventHubamespaceAutoInflate.js rename to plugins/azure/eventhub/eventHubNamespaceAutoInflate.js diff --git a/plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js similarity index 100% rename from plugins/azure/eventhub/eventHubamespaceAutoInflate.spec.js rename to plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js From 4a79a95e3848fcc9eede51bcd308c3fc565ed5e6 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 18:39:37 +0500 Subject: [PATCH 49/73] M/Requested-Changes --- .../eventhub/eventHubNamespaceAutoInflate.js | 27 +++++----- .../eventHubNamespaceAutoInflate.spec.js | 51 ++++++++++++++++--- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js index aa34facf77..4838725d40 100644 --- a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js +++ b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js @@ -3,11 +3,11 @@ var async = require('async'); const helpers = require('../../../helpers/azure'); module.exports = { - title: 'Event Hubs Namespace Auto Inflate Enabled', + title: 'Event Hubs Namespace Auto-Inflate Enabled', category: 'Event Hubs', domain: 'Content Delivery', severity: 'Low', - description: 'Ensure that Event Hubs namespaces have Auto Inflate feature enabled.', + description: 'Ensure that Event Hubs namespaces have Auto-inflate feature enabled.', more_info: 'Enabling Auto-inflate for your Azure Event Hubs namespace ensures seamless scaling by automatically adjusting the number of throughput units (TUs) based on workload demands. This feature helps prevent throttling issues by scaling up as needed, providing efficient and reliable data handling without manual intervention.', recommended_action: 'Modify Event Hub namespace and enable auto-inflate feature.', link: 'https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-auto-inflate', @@ -36,22 +36,25 @@ module.exports = { return rcb(); } - for (let eventHub of eventHubs.data){ + for (let eventHub of eventHubs.data) { if (!eventHub.id) continue; - if (eventHub.sku && - eventHub.sku.tier && - eventHub.sku.tier.toLowerCase() != 'standard') continue; - - if (eventHub.isAutoInflateEnabled){ + if (eventHub.sku && + eventHub.sku.tier && + eventHub.sku.tier.toLowerCase() != 'standard') { helpers.addResult(results, 0, - 'Event Hubs namespace has auto inflate feature enabled',location, eventHub.id); + 'Event Hubs namespace is not a standard namespace', location, eventHub.id); } else { - helpers.addResult(results, 2, - 'Event Hubs namespace does not have auto inflate feature enabled', location, eventHub.id); + if (eventHub.isAutoInflateEnabled) { + helpers.addResult(results, 0, + 'Event Hubs namespace has auto inflate feature enabled', location, eventHub.id); + } else { + helpers.addResult(results, 2, + 'Event Hubs namespace does not have auto inflate feature enabled', location, eventHub.id); + } } } - + rcb(); }, function() { callback(null, results, source); diff --git a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js index bc9d382ed3..c642983c19 100644 --- a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js +++ b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js @@ -1,6 +1,5 @@ var expect = require('chai').expect; -var eventHubamespaceAutoInflate = require('./eventHubamespaceAutoInflate'); - +var eventHubNamespaceAutoInflate = require('./eventHubNamespaceAutoInflate'); const eventHubs = [ { "kind": "v12.0", @@ -18,11 +17,33 @@ const eventHubs = [ "isAutoInflateEnabled": true, "maximumThroughputUnits": 0, "kafkaEnabled": false, - "identity": { - "principalId": "12345", - "tenantId": "123243546", - "type": "SystemAssigned" + "sku": { + "name": "Standard", + "tier": "Standard", + "capacity": 1 + }, }, + { + "kind": "v12.0", + "location": "eastus", + "tags": {}, + "id": "/subscriptions/123/resourceGroups/test-rg/providers/Microsoft.EventHub/namespaces/testHub'", + "name": "testHub", + "type": 'Microsoft.EventHub/Namespaces', + "location": 'East US', + "tags": {}, + "minimumTlsVersion": '1.1', + "publicNetworkAccess": 'Enabled', + "disableLocalAuth": true, + "zoneRedundant": true, + "isAutoInflateEnabled": false, + "maximumThroughputUnits": 0, + "kafkaEnabled": false, + "sku": { + "name": "Standard", + "tier": "Standard", + "capacity": 1 + }, }, { "kind": "v12.0", @@ -40,6 +61,11 @@ const eventHubs = [ "isAutoInflateEnabled": false, "maximumThroughputUnits": 0, "kafkaEnabled": false, + "sku": { + "name": "Premium", + "tier": "Premium", + "capacity": 1 + }, } ]; @@ -108,5 +134,18 @@ describe('eventHubamespaceAutoInflate', function() { const cache = createCache(null); eventHubamespaceAutoInflate.run(cache, {}, callback); }); + + it('should give passing result if event hub namespace is not standard type', 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('Event Hubs namespace is not standard namespace'); + expect(results[0].region).to.equal('eastus'); + done() + }; + + const cache = createCache([eventHubs[2]]); + eventHubamespaceAutoInflate.run(cache, {}, callback); + }); }) }) \ No newline at end of file From d561b9caf3853740c1d4ec5837ad1326aa9eff20 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 18:49:22 +0500 Subject: [PATCH 50/73] M/exports.js --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 310e7b25b5..30a67c0cb4 100644 --- a/exports.js +++ b/exports.js @@ -1109,7 +1109,7 @@ module.exports = { 'eventHubMinimumTLSversion' : require(__dirname + '/plugins/azure/eventhub/eventHubMinimumTLSversion.js'), 'eventHubNamespaceHasTags' : require(__dirname + '/plugins/azure/eventhub/eventHubNamespaceHasTags.js'), - 'eventHubamespaceAutoInflate' : require(__dirname + '/plugins/azure/eventhub/eventHubamespaceAutoInflate.js'), + 'eventHubNamespaceAutoInflate' : require(__dirname + '/plugins/azure/eventhub/eventHubNamespaceAutoInflate.js'), 'eventHubLocalAuthDisabled' : require(__dirname + '/plugins/azure/eventhub/eventHubLocalAuthDisabled.js'), 'eventHubPublicAccess' : require(__dirname + '/plugins/azure/eventhub/eventHubPublicAccess.js'), 'eventHubNamespaceCmkEncrypted' : require(__dirname + '/plugins/azure/eventhub/eventHubNamespaceCmkEncrypted.js'), From f969046daf5ddf7b51b114aeaeff406bdd4338fb Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 18:55:47 +0500 Subject: [PATCH 51/73] fixed test --- .../eventhub/eventHubNamespaceAutoInflate.spec.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js index c642983c19..9a4494f324 100644 --- a/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js +++ b/plugins/azure/eventhub/eventHubNamespaceAutoInflate.spec.js @@ -81,7 +81,7 @@ const createCache = (hub) => { } }; -describe('eventHubamespaceAutoInflate', function() { +describe('eventHubNamespaceAutoInflate', function() { describe('run', function() { it('should give passing result if no event hub found', function(done) { const callback = (err, results) => { @@ -93,7 +93,7 @@ describe('eventHubamespaceAutoInflate', function() { }; const cache = createCache([]); - eventHubamespaceAutoInflate.run(cache, {}, callback); + eventHubNamespaceAutoInflate.run(cache, {}, callback); }); it('should give failing result if Event Hubs namespace does not have auto-inflate feature enabled', function(done) { @@ -106,7 +106,7 @@ describe('eventHubamespaceAutoInflate', function() { }; const cache = createCache([eventHubs[1]]); - eventHubamespaceAutoInflate.run(cache, {}, callback); + eventHubNamespaceAutoInflate.run(cache, {}, callback); }); it('should give passing result if Event Hubs namespace has auto-inflate feature enabled', function(done) { @@ -119,7 +119,7 @@ describe('eventHubamespaceAutoInflate', function() { }; const cache = createCache([eventHubs[0]]); - eventHubamespaceAutoInflate.run(cache, {}, callback); + eventHubNamespaceAutoInflate.run(cache, {}, callback); }); it('should give unknown result if unable to query for event hubs', function(done) { @@ -132,20 +132,20 @@ describe('eventHubamespaceAutoInflate', function() { }; const cache = createCache(null); - eventHubamespaceAutoInflate.run(cache, {}, callback); + eventHubNamespaceAutoInflate.run(cache, {}, callback); }); it('should give passing result if event hub namespace is not standard type', 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('Event Hubs namespace is not standard namespace'); + expect(results[0].message).to.include('Event Hubs namespace is not a standard namespace'); expect(results[0].region).to.equal('eastus'); done() }; const cache = createCache([eventHubs[2]]); - eventHubamespaceAutoInflate.run(cache, {}, callback); + eventHubNamespaceAutoInflate.run(cache, {}, callback); }); }) }) \ No newline at end of file From d2c37ab0549dbd5ed0394a0e170f56fa01b3a523 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 19:03:17 +0500 Subject: [PATCH 52/73] Apply suggestions from code review --- plugins/azure/batchAccounts/batchAccountsPublicAccess.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure/batchAccounts/batchAccountsPublicAccess.js b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js index 892df4a591..505ed92048 100644 --- a/plugins/azure/batchAccounts/batchAccountsPublicAccess.js +++ b/plugins/azure/batchAccounts/batchAccountsPublicAccess.js @@ -7,8 +7,8 @@ module.exports = { domain: 'Compute', severity: 'Medium', description: 'Ensures that Batch accounts are not publicly accessible.', - more_info: 'Disabling public access for your Azure Batch Account enhances security by restricting unauthorized access to your batch resources. This setting ensures that only trusted, internal sources can interact with your batch services, protecting your data and processes from potential external threats.', - recommended_action: 'Modify Batch Account and disable public access.', + more_info: 'Disabling public access for your Azure Batch Account enhances security by restricting unauthorized access to resources. This setting ensures that only trusted, internal sources can interact with Batch services, protecting data from potential external threats.', + recommended_action: 'Modify Batch account and disable public access.', link: 'https://learn.microsoft.com/en-us/azure/batch/public-network-access', apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], From 63d4791585341f712827382036a66bcdef706223 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sat, 15 Jun 2024 19:15:54 +0500 Subject: [PATCH 53/73] Apply suggestions from code review --- plugins/azure/batchAccounts/batchAccountsAADEnabled.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js index 3987251a7f..ea487558fe 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -6,10 +6,10 @@ module.exports = { category: 'Batch', domain: 'Compute', severity: 'Medium', - description: 'Ensures that Batch account has AAD authentication mode enabled.', - more_info: 'Enabling AAD Authentication for your Azure Batch Account ensures enhanced security by utilizing a robust authentication method required for several security-related features. By restricting the service API authentication to Microsoft Entra ID, you prevent access through less secure shared key methods, thereby safeguarding your batch resources from unauthorized access.', + description: 'Ensures that Batch account has Azure Active Directory (AAD) authentication mode enabled.', + more_info: 'Enabling Azure Active Directory (AAD) authentication for Batch account ensures enhanced security by restricting the service API authentication to Microsoft Entra ID that prevents access through less secure shared key methods, thereby safeguarding batch resources from unauthorized access.', recommended_action: 'Enable diagnostic logging for all Batch accounts.', - link: 'https://learn.microsoft.com/en-us/azure/batch/security-best-practices#batch-account-authentication', + link: 'https://learn.microsoft.com/en-us/azure/batch/batch-aad-auth', apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], From e0588da6ce2587f58aa4a2c6b65f69883d3e76ff Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 19:23:07 +0500 Subject: [PATCH 54/73] H-plugin/batch-account-aad-enabled --- .../batchAccounts/batchAccountsAADEnabled.js | 35 ++++++++----------- .../batchAccountsAADEnabled.spec.js | 4 +-- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js index ea487558fe..311700f8bc 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -11,14 +11,14 @@ module.exports = { recommended_action: 'Enable diagnostic logging for all Batch accounts.', link: 'https://learn.microsoft.com/en-us/azure/batch/batch-aad-auth', apis: ['batchAccounts:list'], - realtime_triggers: ['microsoftbatch:batchaccounts:write','microsoftbatch:batchaccounts:delete'], + realtime_triggers: ['microsoftbatch:batchaccounts:write', 'microsoftbatch:batchaccounts:delete'], - run: function(cache, settings, callback) { + run: function (cache, settings, callback) { var results = []; var source = {}; var locations = helpers.locations(settings.govcloud); - async.each(locations.batchAccounts, function(location, rcb){ + async.each(locations.batchAccounts, function (location, rcb) { var batchAccounts = helpers.addSource(cache, source, ['batchAccounts', 'list', location]); @@ -34,30 +34,23 @@ module.exports = { return rcb(); } - for (let batchAccount of batchAccounts.data) { + for (let batchAccount of batchAccounts.data) { if (!batchAccount.id) continue; - - let found = false; - if (batchAccount.allowedAuthenticationModes && - batchAccount.allowedAuthenticationModes.length) { - batchAccount.allowedAuthenticationModes.forEach(mode => { - if (mode.toUpperCase() == 'AAD') { - found = true; - } - }); - if (found) { - helpers.addResult(results, 0, 'Batch account is configured with AAD Authentication', location, batchAccount.id); - } else { - helpers.addResult(results, 2, 'Batch account is not configured with AAD Authentication', location, batchAccount.id); - } + let found = batchAccount.allowedAuthenticationModes && + batchAccount.allowedAuthenticationModes.length? + batchAccount.allowedAuthenticationModes.some(mode => mode.toUpperCase() === 'AAD') : false; + + if (found) { + helpers.addResult(results, 0, 'Batch account has Active Directory authentication enabled', location, batchAccount.id); } else { - helpers.addResult(results, 2, 'Batch account is not configured with AAD Authentication', location, batchAccount.id); + helpers.addResult(results, 2, 'Batch account does not have Active Directory authentication enabled', location, batchAccount.id); } + } - + rcb(); - }, function() { + }, function () { callback(null, results, source); }); } diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js index 0cc332ea70..cd106bc09f 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.spec.js @@ -74,7 +74,7 @@ describe('batchAccountsAADEnabled', function () { batchAccountsAADEnabled.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('Batch account is configured with AAD Authentication'); + expect(results[0].message).to.include('Batch account has Active Directory authentication enabled'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -85,7 +85,7 @@ describe('batchAccountsAADEnabled', function () { batchAccountsAADEnabled.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('Batch account is not configured with AAD Authentication'); + expect(results[0].message).to.include('Batch account does not have Active Directory authentication enabled'); expect(results[0].region).to.equal('eastus'); done(); }); From 1279911a35178a85582e18782171dd7a8537af0d Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sat, 15 Jun 2024 19:24:36 +0500 Subject: [PATCH 55/73] M/fixed-linting --- plugins/azure/batchAccounts/batchAccountsAADEnabled.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js index 311700f8bc..f327d1665f 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -13,12 +13,12 @@ module.exports = { apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write', 'microsoftbatch:batchaccounts:delete'], - run: function (cache, settings, callback) { + run: function(cache, settings, callback) { var results = []; var source = {}; var locations = helpers.locations(settings.govcloud); - async.each(locations.batchAccounts, function (location, rcb) { + async.each(locations.batchAccounts, function(location, rcb) { var batchAccounts = helpers.addSource(cache, source, ['batchAccounts', 'list', location]); @@ -39,7 +39,7 @@ module.exports = { let found = batchAccount.allowedAuthenticationModes && batchAccount.allowedAuthenticationModes.length? - batchAccount.allowedAuthenticationModes.some(mode => mode.toUpperCase() === 'AAD') : false; + batchAccount.allowedAuthenticationModes.some(mode => mode.toUpperCase() === 'AAD') : false; if (found) { helpers.addResult(results, 0, 'Batch account has Active Directory authentication enabled', location, batchAccount.id); @@ -50,7 +50,7 @@ module.exports = { } rcb(); - }, function () { + }, function() { callback(null, results, source); }); } From 784a4f69dca9f43b50f405c8037f5d04f05316cd Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 16 Jun 2024 15:10:49 +0500 Subject: [PATCH 56/73] M/Requested-Changes --- config_example.js | 8 ++++---- exports.js | 2 +- ...oint.js => synapseWorkspacPrivateEndpoint.js} | 12 +++++++----- ...js => synapseWorkspacPrivateEndpoint.spec.js} | 16 ++++++++-------- 4 files changed, 20 insertions(+), 18 deletions(-) rename plugins/azure/synapse/{workspacePrivateEndpoint.js => synapseWorkspacPrivateEndpoint.js} (66%) rename plugins/azure/synapse/{workspacePrivateEndpoint.spec.js => synapseWorkspacPrivateEndpoint.spec.js} (81%) diff --git a/config_example.js b/config_example.js index e943ad61d9..da1a4ef9cf 100644 --- a/config_example.js +++ b/config_example.js @@ -30,10 +30,10 @@ module.exports = { // OPTION 1: If using a credential JSON file, enter the path below // credential_file: '/path/to/file.json', // OPTION 2: If using hard-coded credentials, enter them below - // 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 || '', + application_id: process.env.AZURE_APPLICATION_ID || '17e14067-428b-4746-9483-ea033812e642', + key_value: process.env.AZURE_KEY_VALUE || 'VMn8Q~7qds5YBfo7xWh4HRuDybKNIkmOkFMqadtq', + directory_id: process.env.AZURE_DIRECTORY_ID || 'd207c7bd-fcb1-4dd3-855a-cfd2f9b651e8', + subscription_id: process.env.AZURE_SUBSCRIPTION_ID || '26a1a07e-06dd-4892-92c9-e4996b0fc546' // storage_connection: process.env.AZURE_STORAGE_CONNECTION || '', // blob_container: process.env.AZURE_BLOB_CONTAINER || '', // govcloud: process.env.AZURE_GOV_CLOUD || '' diff --git a/exports.js b/exports.js index fe6f7c8a2b..7c9c21f00e 100644 --- a/exports.js +++ b/exports.js @@ -1195,7 +1195,7 @@ module.exports = { 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), - 'workspacePrivateEndpoint' : require(__dirname + '/plugins/azure/synapse/workspacePrivateEndpoint.js'), + 'synapseWorkspacPrivateEndpoint': require(__dirname + '/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js'), }, github: { diff --git a/plugins/azure/synapse/workspacePrivateEndpoint.js b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js similarity index 66% rename from plugins/azure/synapse/workspacePrivateEndpoint.js rename to plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js index ff3805a8bf..7f8c3c4d12 100644 --- a/plugins/azure/synapse/workspacePrivateEndpoint.js +++ b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js @@ -6,10 +6,10 @@ module.exports = { category: 'AI & ML', domain: 'Machine Learning', severity: 'Medium', - description: 'Ensure that Azure Synapse Analytics Workspace are accessible only through private endpoints.', - more_info: 'Azure Private Endpoint is a network interface that connects you privately and securely to a service powered by Azure Private Link. Private Endpoint uses a private IP address from your VNet, effectively bringing the service such as Azure Storage Accounts into your VNet.', + description: 'Ensure that Azure Synapse Workspace is accessible only through managed private endpoints.', + more_info: 'Enabling managed private endpoints for Azure Synapse Analytics ensure secure, private communication between your Synapse workspace and other Azure resources, traversing exclusively over the Microsoft backbone network. It enhances security by protecting against data exfiltration and allowing connectivity only to specific approved resources.', recommended_action: 'Modify Synapse Workspace and configure private endpoints.', - link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/security/how-to-connect-to-workspace-with-private-links', + link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/security/synapse-workspace-managed-private-endpoints', apis: ['synapse:listWorkspaces'], realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], @@ -36,11 +36,13 @@ module.exports = { } for (let workspace of workspaces.data) { + if (!workspace.id) continue; + if (workspace.privateEndpointConnections && workspace.privateEndpointConnections.length) { - helpers.addResult(results, 0, 'Private endpoints are configured for the Synapse workspace', location, workspace.id); + helpers.addResult(results, 0, 'Synapse workspace has managed private endpoints configured', location, workspace.id); } else { - helpers.addResult(results, 2, 'Private endpoints are not configured for the Synapse workspace', location, workspace.id); + helpers.addResult(results, 2, 'Synapse workspace does not have managed private endpoints configured', location, workspace.id); } } diff --git a/plugins/azure/synapse/workspacePrivateEndpoint.spec.js b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.spec.js similarity index 81% rename from plugins/azure/synapse/workspacePrivateEndpoint.spec.js rename to plugins/azure/synapse/synapseWorkspacPrivateEndpoint.spec.js index 55094afe1d..6aa7a0a3f0 100644 --- a/plugins/azure/synapse/workspacePrivateEndpoint.spec.js +++ b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.spec.js @@ -1,5 +1,5 @@ var expect = require('chai').expect; -var workspacePrivateEndpoint = require('./workspacePrivateEndpoint'); +var synapseWorkspacPrivateEndpoint = require('./synapseWorkspacPrivateEndpoint'); const workspaces = [ { @@ -44,12 +44,12 @@ const createCache = (workspaces, err) => { }; }; -describe('workspacePrivateEndpoint', function () { +describe('synapseWorkspacPrivateEndpoint', function () { describe('run', function () { it('should give a passing result if no Synapse workspaces are found', function (done) { const cache = createCache([], null); - workspacePrivateEndpoint.run(cache, {}, (err, results) => { + synapseWorkspacPrivateEndpoint.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 Synapse workspaces found'); @@ -60,7 +60,7 @@ describe('workspacePrivateEndpoint', function () { it('should give unknown result if unable to query for Synapse workspaces', function (done) { const cache = createCache(null, ['error']); - workspacePrivateEndpoint.run(cache, {}, (err, results) => { + synapseWorkspacPrivateEndpoint.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 Synapse workspaces'); @@ -71,10 +71,10 @@ describe('workspacePrivateEndpoint', function () { it('should give passing result if workspace has Private endpoints configured ', function (done) { const cache = createCache([workspaces[0]], null); - workspacePrivateEndpoint.run(cache, {}, (err, results) => { + synapseWorkspacPrivateEndpoint.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('Private endpoints are configured for the Synapse workspace'); + expect(results[0].message).to.include('Synapse workspace has managed private endpoints configured'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -82,10 +82,10 @@ describe('workspacePrivateEndpoint', function () { it('should give failing result if workspace does not have Private endpoints configured', function (done) { const cache = createCache([workspaces[1]], null); - workspacePrivateEndpoint.run(cache, {}, (err, results) => { + synapseWorkspacPrivateEndpoint.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('Private endpoints are not configured for the Synapse workspace'); + expect(results[0].message).to.include('Synapse workspace does not have managed private endpoints configured'); expect(results[0].region).to.equal('eastus'); done(); }); From 5c6e8351c8e50b97c2eb96d0651855a60c7464a2 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 16 Jun 2024 15:12:45 +0500 Subject: [PATCH 57/73] M/Requested-Changes --- config_example.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config_example.js b/config_example.js index da1a4ef9cf..e943ad61d9 100644 --- a/config_example.js +++ b/config_example.js @@ -30,10 +30,10 @@ module.exports = { // OPTION 1: If using a credential JSON file, enter the path below // credential_file: '/path/to/file.json', // OPTION 2: If using hard-coded credentials, enter them below - application_id: process.env.AZURE_APPLICATION_ID || '17e14067-428b-4746-9483-ea033812e642', - key_value: process.env.AZURE_KEY_VALUE || 'VMn8Q~7qds5YBfo7xWh4HRuDybKNIkmOkFMqadtq', - directory_id: process.env.AZURE_DIRECTORY_ID || 'd207c7bd-fcb1-4dd3-855a-cfd2f9b651e8', - subscription_id: process.env.AZURE_SUBSCRIPTION_ID || '26a1a07e-06dd-4892-92c9-e4996b0fc546' + // 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 || '', // storage_connection: process.env.AZURE_STORAGE_CONNECTION || '', // blob_container: process.env.AZURE_BLOB_CONTAINER || '', // govcloud: process.env.AZURE_GOV_CLOUD || '' From 28876928bc6ccce776b68f264bc8b687bed21214 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:14:31 +0500 Subject: [PATCH 58/73] Apply suggestions from code review --- plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js index 7f8c3c4d12..c375d75561 100644 --- a/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js +++ b/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js @@ -6,9 +6,9 @@ module.exports = { category: 'AI & ML', domain: 'Machine Learning', severity: 'Medium', - description: 'Ensure that Azure Synapse Workspace is accessible only through managed private endpoints.', - more_info: 'Enabling managed private endpoints for Azure Synapse Analytics ensure secure, private communication between your Synapse workspace and other Azure resources, traversing exclusively over the Microsoft backbone network. It enhances security by protecting against data exfiltration and allowing connectivity only to specific approved resources.', - recommended_action: 'Modify Synapse Workspace and configure private endpoints.', + description: 'Ensure that Azure Synapse workspace is accessible only through managed private endpoints.', + more_info: 'Enabling managed private endpoints for Azure Synapse Analytics workspace ensure secure, private communication between your Synapse workspace and other Azure resources, traversing exclusively over the Microsoft backbone network. It enhances security by protecting against data exfiltration and allowing connectivity only to specific approved resources.', + recommended_action: 'Modify Synapse workspace and configure managed private endpoints.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/security/synapse-workspace-managed-private-endpoints', apis: ['synapse:listWorkspaces'], realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], From 88d31063b626c9af86e0de96fe944262a91d557e Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:46:27 +0500 Subject: [PATCH 59/73] Update plugins/azure/batchAccounts/batchAccountsAADEnabled.js --- plugins/azure/batchAccounts/batchAccountsAADEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js index f327d1665f..c0372be580 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -8,7 +8,7 @@ module.exports = { severity: 'Medium', description: 'Ensures that Batch account has Azure Active Directory (AAD) authentication mode enabled.', more_info: 'Enabling Azure Active Directory (AAD) authentication for Batch account ensures enhanced security by restricting the service API authentication to Microsoft Entra ID that prevents access through less secure shared key methods, thereby safeguarding batch resources from unauthorized access.', - recommended_action: 'Enable diagnostic logging for all Batch accounts.', + recommended_action: 'Enable Active Directory (AD) authentication mode for all Batch accounts.', link: 'https://learn.microsoft.com/en-us/azure/batch/batch-aad-auth', apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write', 'microsoftbatch:batchaccounts:delete'], From 477e415aa0448e7ed968c0380ec993a46737482f Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 16 Jun 2024 16:01:52 +0500 Subject: [PATCH 60/73] M/Requested-Changes --- exports.js | 3 +-- ...abled.js => synapseWorkspaceAdAuthEnabled.js} | 14 ++++++++------ ....js => synapseWorkspaceAdAuthEnabled.spec.js} | 16 ++++++++-------- 3 files changed, 17 insertions(+), 16 deletions(-) rename plugins/azure/synapse/{workspaceAADAuthEnabled.js => synapseWorkspaceAdAuthEnabled.js} (68%) rename plugins/azure/synapse/{workspaceAADAuthEnabled.spec.js => synapseWorkspaceAdAuthEnabled.spec.js} (82%) diff --git a/exports.js b/exports.js index 7c0d015b90..1e3c0c5830 100644 --- a/exports.js +++ b/exports.js @@ -1195,8 +1195,7 @@ module.exports = { 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), - 'workspaceAADAuthEnabled' : require(__dirname + '/plugins/azure/synapse/workspaceAADAuthEnabled.js'), - + 'synapseWorkspaceAdAuthEnabled' : require(__dirname + '/plugins/azure/synapse/workspaceAADAuthEnabled.js'), }, github: { 'publicKeysRotated' : require(__dirname + '/plugins/github/users/publicKeysRotated.js'), diff --git a/plugins/azure/synapse/workspaceAADAuthEnabled.js b/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.js similarity index 68% rename from plugins/azure/synapse/workspaceAADAuthEnabled.js rename to plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.js index c7a5454713..80606b792a 100644 --- a/plugins/azure/synapse/workspaceAADAuthEnabled.js +++ b/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.js @@ -2,13 +2,13 @@ var async = require('async'); var helpers = require('../../../helpers/azure'); module.exports = { - title: 'Synapse Workspace AAD Auth Enabled', + title: 'Synapse Workspace AD Auth Enabled', category: 'AI & ML', domain: 'Machine Learning', severity: 'Medium', - description: 'Ensure that Azure Synapse Analytics Workspace have AAD Auth enabled.', - more_info: 'Enabling Microsoft Entra ID (AAD) Authentication for your Synapse workspace enhances security by ensuring that only authenticated and authorized users can access your resources. This feature integrates seamlessly with AAD, providing robust access control and simplifying user management.', - recommended_action: 'Modify Synapse Workspace and enable microsoft entra id authentication.', + description: 'Ensures that Azure Synapse workspace has Active Directory (AD) authentication enabled.', + more_info: 'Enabling Azure Active Directory authentication for Synapse workspace enhances security by ensuring that only authenticated and authorized users can access resources and eliminating the need for password storage. This integration simplifies permission management and secure access.', + recommended_action: 'Enable Active Directory (AD) authentication mode for all Synapse workspace.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/sql/active-directory-authentication', apis: ['synapse:listWorkspaces'], realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], @@ -36,10 +36,12 @@ module.exports = { } for (let workspace of workspaces.data) { + if (!workspace.id) continue; + if (workspace.azureADOnlyAuthentication) { - helpers.addResult(results, 0, 'Synapse workspace has AAD auth enabled', location, workspace.id); + helpers.addResult(results, 0, 'Synapse workspace has Active Directory authentication enabled', location, workspace.id); } else { - helpers.addResult(results, 2, 'Synapse workspace does not have AAD auth enabled', location, workspace.id); + helpers.addResult(results, 2, 'Synapse workspace does not have Active Directory authentication enabled', location, workspace.id); } } diff --git a/plugins/azure/synapse/workspaceAADAuthEnabled.spec.js b/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.spec.js similarity index 82% rename from plugins/azure/synapse/workspaceAADAuthEnabled.spec.js rename to plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.spec.js index c4978ac19a..0db95cd9eb 100644 --- a/plugins/azure/synapse/workspaceAADAuthEnabled.spec.js +++ b/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.spec.js @@ -1,5 +1,5 @@ var expect = require('chai').expect; -var workspaceAADAuthEnabled = require('./workspaceAADAuthEnabled'); +var synapseWorkspaceAdAuthEnabled = require('./synapseWorkspaceAdAuthEnabled'); const workspaces = [ { @@ -32,12 +32,12 @@ const createCache = (workspaces, err) => { }; }; -describe('workspaceAADAuthEnabled', function () { +describe('synapseWorkspaceAdAuthEnabled', function () { describe('run', function () { it('should give a passing result if no Synapse workspaces are found', function (done) { const cache = createCache([], null); - workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + synapseWorkspaceAdAuthEnabled.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 Synapse workspaces found'); @@ -48,7 +48,7 @@ describe('workspaceAADAuthEnabled', function () { it('should give unknown result if unable to query for Synapse workspaces', function (done) { const cache = createCache(null, ['error']); - workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + synapseWorkspaceAdAuthEnabled.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 Synapse workspaces'); @@ -59,10 +59,10 @@ describe('workspaceAADAuthEnabled', function () { it('should give passing result if workspace has AAD auth enabled', function (done) { const cache = createCache([workspaces[0]], null); - workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + synapseWorkspaceAdAuthEnabled.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('Synapse workspace has AAD auth enabled'); + expect(results[0].message).to.include('Synapse workspace has Active Directory authentication enabled'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -70,10 +70,10 @@ describe('workspaceAADAuthEnabled', function () { it('should give failing result if workspace does not have AAD auth', function (done) { const cache = createCache([workspaces[1]], null); - workspaceAADAuthEnabled.run(cache, {}, (err, results) => { + synapseWorkspaceAdAuthEnabled.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('Synapse workspace does not have AAD auth enabled'); + expect(results[0].message).to.include('Synapse workspace does not have Active Directory authentication enabled'); expect(results[0].region).to.equal('eastus'); done(); }); From 8e802867c3ed391586d524b1b77a12376a1afa87 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Sun, 16 Jun 2024 16:02:24 +0500 Subject: [PATCH 61/73] plugin/synaps-workspace-aad-auth-only --- exports.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exports.js b/exports.js index 1e3c0c5830..2ffc2a933e 100644 --- a/exports.js +++ b/exports.js @@ -1195,7 +1195,7 @@ module.exports = { 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), - 'synapseWorkspaceAdAuthEnabled' : require(__dirname + '/plugins/azure/synapse/workspaceAADAuthEnabled.js'), + 'synapseWorkspaceAdAuthEnabled' : require(__dirname + '/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.js'), }, github: { 'publicKeysRotated' : require(__dirname + '/plugins/github/users/publicKeysRotated.js'), From a4b381b9aff3c839a9b542bb9ecebe81908fee6b Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:05:15 +0500 Subject: [PATCH 62/73] Update plugins/azure/batchAccounts/batchAccountsAADEnabled.js --- plugins/azure/batchAccounts/batchAccountsAADEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js index c0372be580..cf9cabc3ad 100644 --- a/plugins/azure/batchAccounts/batchAccountsAADEnabled.js +++ b/plugins/azure/batchAccounts/batchAccountsAADEnabled.js @@ -8,7 +8,7 @@ module.exports = { severity: 'Medium', description: 'Ensures that Batch account has Azure Active Directory (AAD) authentication mode enabled.', more_info: 'Enabling Azure Active Directory (AAD) authentication for Batch account ensures enhanced security by restricting the service API authentication to Microsoft Entra ID that prevents access through less secure shared key methods, thereby safeguarding batch resources from unauthorized access.', - recommended_action: 'Enable Active Directory (AD) authentication mode for all Batch accounts.', + recommended_action: 'Enable Active Directory authentication mode for all Batch accounts.', link: 'https://learn.microsoft.com/en-us/azure/batch/batch-aad-auth', apis: ['batchAccounts:list'], realtime_triggers: ['microsoftbatch:batchaccounts:write', 'microsoftbatch:batchaccounts:delete'], From a8d321c7963bb6cc61c79a675533661a8b60ac1d Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:24:37 +0500 Subject: [PATCH 63/73] Apply suggestions from code review --- plugins/azure/synapse/workspaceManagedIdentity.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/azure/synapse/workspaceManagedIdentity.js b/plugins/azure/synapse/workspaceManagedIdentity.js index 028748792c..51e45b6c04 100644 --- a/plugins/azure/synapse/workspaceManagedIdentity.js +++ b/plugins/azure/synapse/workspaceManagedIdentity.js @@ -6,9 +6,9 @@ module.exports = { category: 'AI & ML', domain: 'Machine Learning', severity: 'Medium', - description: 'Ensure that Azure Synapse Analytics Workspace have managed identity enabled.', + description: 'Ensure that Azure Synapse workspace has managed identity enabled.', more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', - recommended_action: 'Modify Synapse Workspace and enable managed identity.', + recommended_action: 'Modify Synapse workspace and enable managed identity.', link: 'https://learn.microsoft.com/en-us/azure/synapse-analytics/synapse-service-identity', apis: ['synapse:listWorkspaces'], realtime_triggers: ['microsoftsynapse:workspaces:write','microsoftsynapse:workspaces:delete'], @@ -36,7 +36,9 @@ module.exports = { } for (let workspace of workspaces.data) { - if (workspace.identity && workspace.identity) { + if (!workspace.id) continue; + + if (workspace.identity && workspace.identity.type) { helpers.addResult(results, 0, 'Synapse workspace has managed identity enabled', location, workspace.id); } else { helpers.addResult(results, 2, 'Synapse workspace does not have managed identity enabled', location, workspace.id); From 25eee3188b1851d406757b5caf352e60f923d94b Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:40:40 +0500 Subject: [PATCH 64/73] Apply suggestions from code review --- plugins/aws/documentDB/docdbClusterProfilerEnabled.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js index fc728dea23..15d8f83fed 100644 --- a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js +++ b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js @@ -5,10 +5,10 @@ module.exports = { title: 'DocumentDB Cluster Profiler Enabled', category: 'DocumentDB', domain: 'Databases', - severity: 'Medium', + severity: 'Low', description: 'Ensure that Amazon DocumentDB clusters have profiler feature enabled.', - more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps you to monitor and log slow database operations. This makes it easier to identify and fix performance issues by analyzing detailed logs in Amazon CloudWatch.', - recommended_action: 'Modify DocumentDb cluster and enable profiler feature.', + more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps to monitor and log database operations. This makes it easier to identify slowest operations on cluster and fix performance issues by analyzing detailed logs in Amazon CloudWatch. + recommended_action: 'Modify DocumentDB cluster and enable profiler feature.', link: 'https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html', apis: ['DocDB:describeDBClusters'], realtime_triggers: ['docdb:CreateDBCluster','docdb:ModifyDBCluster','docdb:DeleteDBCluster'], From 70784d8cdbff9707146c03c1d43638292b377fdd Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 16:41:36 +0500 Subject: [PATCH 65/73] Update plugins/aws/documentDB/docdbClusterProfilerEnabled.js --- plugins/aws/documentDB/docdbClusterProfilerEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js index 15d8f83fed..35d490c472 100644 --- a/plugins/aws/documentDB/docdbClusterProfilerEnabled.js +++ b/plugins/aws/documentDB/docdbClusterProfilerEnabled.js @@ -7,7 +7,7 @@ module.exports = { domain: 'Databases', severity: 'Low', description: 'Ensure that Amazon DocumentDB clusters have profiler feature enabled.', - more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps to monitor and log database operations. This makes it easier to identify slowest operations on cluster and fix performance issues by analyzing detailed logs in Amazon CloudWatch. + more_info: 'Enabling the Profiler for your Amazon DocumentDB clusters helps to monitor and log database operations. This makes it easier to identify slowest operations on cluster and fix performance issues by analyzing detailed logs in Amazon CloudWatch.', recommended_action: 'Modify DocumentDB cluster and enable profiler feature.', link: 'https://docs.aws.amazon.com/documentdb/latest/developerguide/profiling.html', apis: ['DocDB:describeDBClusters'], From 593434818a4b7b0bfa8d671d8c1160a2b1cbe43a Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:14:19 +0500 Subject: [PATCH 66/73] Apply suggestions from code review --- plugins/azure/apiManagement/apiInstanceManagedIdentity.js | 6 +++--- .../azure/apiManagement/apiInstanceManagedIdentity.spec.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js index 256f0487e8..e36b5f65a8 100644 --- a/plugins/azure/apiManagement/apiInstanceManagedIdentity.js +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js @@ -6,7 +6,7 @@ module.exports = { category: 'API Management', domain: 'Developer Tools', severity: 'Medium', - description: 'Ensures that Azure API Management service instance has managed identity enabled.', + description: 'Ensures that Azure API Management instance has managed identity enabled.', more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', link: 'https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity', recommended_action: 'Modify API Management instance and add managed identity.', @@ -25,12 +25,12 @@ module.exports = { if (!apiManagementService) return rcb(); if (apiManagementService.err || !apiManagementService.data) { - helpers.addResult(results, 3, 'Unable to query API Management service instances:' + helpers.addError(apiManagementService), location); + helpers.addResult(results, 3, 'Unable to query API Management instances:' + helpers.addError(apiManagementService), location); return rcb(); } if (!apiManagementService.data.length) { - helpers.addResult(results, 0, 'No existing API Management service instances found', location); + helpers.addResult(results, 0, 'No existing API Management instances found', location); return rcb(); } diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js index 3416bf65e7..1d14dcc99e 100644 --- a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js @@ -59,7 +59,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.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 API Management service instances found'); + expect(results[0].message).to.include('No existing API Management instances found'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -70,7 +70,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.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 API Management service instances:'); + expect(results[0].message).to.include('Unable to query API Management instances:'); expect(results[0].region).to.equal('eastus'); done(); }); From 4bb5ad70678a6813ce73ec68cb5a9ff1c58855ef Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:16:50 +0500 Subject: [PATCH 67/73] Update plugins/aws/codebuild/codebuildProjectLoggingEnabled.js --- plugins/aws/codebuild/codebuildProjectLoggingEnabled.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js b/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js index 3304633934..7a89db2003 100644 --- a/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js +++ b/plugins/aws/codebuild/codebuildProjectLoggingEnabled.js @@ -8,7 +8,7 @@ module.exports = { severity: 'Medium', description: 'Ensure that your AWS CodeBuild build project has S3 or Cloudwatch logs enabled.', more_info: 'Monitoring AWS CodeBuild projects helps maintaining the reliability, availability, and performance of the resource. It helps to easily debug multi-point failure and potential incidents.', - recommended_action: 'Modify CodeBuild build project enable logging.', + recommended_action: 'Ensure that CodeBuild project has logging enabled.', link: 'https://docs.aws.amazon.com/codebuild/latest/userguide/monitoring-builds.html', apis: ['CodeBuild:listProjects', 'CodeBuild:batchGetProjects', 'STS:GetCallerIdentity'], realtime_triggers: ['codebuild:CreateProject', 'codebuild:UpdateProject', 'codebuild:DeleteProject'], From 1c74ae4d1b3246935309df9ae1132a0c67a7d6f7 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:25:14 +0500 Subject: [PATCH 68/73] Apply suggestions from code review --- plugins/azure/apiManagement/apiInstanceHasTags.js | 10 +++++----- .../azure/apiManagement/apiInstanceHasTags.spec.js | 12 ++++++------ .../apiManagement/apiInstanceManagedIdentity.js | 10 +++++----- .../apiManagement/apiInstanceManagedIdentity.spec.js | 12 ++++++------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.js b/plugins/azure/apiManagement/apiInstanceHasTags.js index 642f059719..a052b4277f 100644 --- a/plugins/azure/apiManagement/apiInstanceHasTags.js +++ b/plugins/azure/apiManagement/apiInstanceHasTags.js @@ -6,7 +6,7 @@ module.exports = { category: 'API Management', domain: 'Developer Tools', severity: 'Medium', - description: 'Ensures that Azure API Management service instance has tags associated.', + description: 'Ensures that Azure API Management instance has tags associated.', more_info: 'Tags help you to group resources together that are related to or associated with each other. It is a best practice to tag cloud resources to better organize and gain visibility into their usage.', link: 'https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources', recommended_action: 'Modify API Management instance and add tags.', @@ -25,12 +25,12 @@ module.exports = { if (!apiManagementService) return rcb(); if (apiManagementService.err || !apiManagementService.data) { - helpers.addResult(results, 3, 'Unable to query API Management service instances:' + helpers.addError(apiManagementService), location); + helpers.addResult(results, 3, 'Unable to query API Management instances:' + helpers.addError(apiManagementService), location); return rcb(); } if (!apiManagementService.data.length) { - helpers.addResult(results, 0, 'No existing API Management service instances found', location); + helpers.addResult(results, 0, 'No existing API Management instances found', location); return rcb(); } @@ -38,9 +38,9 @@ module.exports = { if (!apiInstance.id) continue; if (apiInstance.tags && Object.entries(apiInstance.tags).length > 0) { - helpers.addResult(results, 0, 'API Management service instance has tags associated', location, apiInstance.id); + helpers.addResult(results, 0, 'API Management service has tags associated', location, apiInstance.id); } else { - helpers.addResult(results, 2, 'API Management service instance does not have tags associated', location, apiInstance.id); + helpers.addResult(results, 2, 'API Management instance does not have tags associated', location, apiInstance.id); } } diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.spec.js b/plugins/azure/apiManagement/apiInstanceHasTags.spec.js index 260c2720a5..b8575e34e9 100644 --- a/plugins/azure/apiManagement/apiInstanceHasTags.spec.js +++ b/plugins/azure/apiManagement/apiInstanceHasTags.spec.js @@ -13,7 +13,7 @@ const apiManagementService = [ "zones": null, "tags": {}, "location": "East US", - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" }, @@ -32,7 +32,7 @@ const apiManagementService = [ "zones": null, "location": "East US", "tags": {"key": "value"}, - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" } @@ -59,7 +59,7 @@ describe('apiInstanceHasTags', function () { apiInstanceHasTags.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 API Management service instances found'); + expect(results[0].message).to.include('No existing API Management instances found'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -70,7 +70,7 @@ describe('apiInstanceHasTags', function () { apiInstanceHasTags.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 API Management service instances'); + expect(results[0].message).to.include('Unable to query API Management instances'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -81,7 +81,7 @@ describe('apiInstanceHasTags', function () { apiInstanceHasTags.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('API Management service instance has tags associated'); + expect(results[0].message).to.include('API Management instance has tags associated'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -92,7 +92,7 @@ describe('apiInstanceHasTags', function () { apiInstanceHasTags.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('API Management service instance does not have tags associated'); + expect(results[0].message).to.include('API Management instance does not have tags associated'); expect(results[0].region).to.equal('eastus'); done(); }); diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js index 256f0487e8..57557b0183 100644 --- a/plugins/azure/apiManagement/apiInstanceManagedIdentity.js +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.js @@ -6,7 +6,7 @@ module.exports = { category: 'API Management', domain: 'Developer Tools', severity: 'Medium', - description: 'Ensures that Azure API Management service instance has managed identity enabled.', + description: 'Ensures that Azure API Management instance has managed identity enabled.', more_info: 'Enabling managed identities eliminate the need for developers having to manage credentials by providing an identity for the Azure resource in Azure AD and using it to obtain Azure Active Directory (Azure AD) tokens.', link: 'https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-use-managed-service-identity', recommended_action: 'Modify API Management instance and add managed identity.', @@ -25,12 +25,12 @@ module.exports = { if (!apiManagementService) return rcb(); if (apiManagementService.err || !apiManagementService.data) { - helpers.addResult(results, 3, 'Unable to query API Management service instances:' + helpers.addError(apiManagementService), location); + helpers.addResult(results, 3, 'Unable to query API Management instances:' + helpers.addError(apiManagementService), location); return rcb(); } if (!apiManagementService.data.length) { - helpers.addResult(results, 0, 'No existing API Management service instances found', location); + helpers.addResult(results, 0, 'No existing API Management instances found', location); return rcb(); } @@ -38,9 +38,9 @@ module.exports = { if (!apiInstance.id) continue; if (apiInstance.identity) { - helpers.addResult(results, 0, 'API Management service instance has managed identity enabled', location, apiInstance.id); + helpers.addResult(results, 0, 'API Management instance has managed identity enabled', location, apiInstance.id); } else { - helpers.addResult(results, 2, 'API Management service instance does not have managed identity enabled', location, apiInstance.id); + helpers.addResult(results, 2, 'API Management instance does not have managed identity enabled', location, apiInstance.id); } } diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js index 3416bf65e7..145736284f 100644 --- a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js @@ -13,7 +13,7 @@ const apiManagementService = [ "zones": null, "location": "East US", "tags": {}, - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" }, @@ -32,7 +32,7 @@ const apiManagementService = [ "zones": null, "location": "East US", "tags": {}, - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" } @@ -59,7 +59,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.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 API Management service instances found'); + expect(results[0].message).to.include('No existing API Management instances found'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -70,7 +70,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.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 API Management service instances:'); + expect(results[0].message).to.include('Unable to query API Management instances:'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -81,7 +81,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(0); - expect(results[0].message).to.include('API Management service instance has managed identity enabled'); + expect(results[0].message).to.include('API Management instance has managed identity enabled'); expect(results[0].region).to.equal('eastus'); done(); }); @@ -92,7 +92,7 @@ describe('apiInstanceManagedIdentity', function () { apiInstanceManagedIdentity.run(cache, {}, (err, results) => { expect(results.length).to.equal(1); expect(results[0].status).to.equal(2); - expect(results[0].message).to.include('API Management service instance does not have managed identity enabled'); + expect(results[0].message).to.include('API Management instance does not have managed identity enabled'); expect(results[0].region).to.equal('eastus'); done(); }); From 0c34b4ba06f1295bfa94c6de308ec8c738424eac Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:29:26 +0500 Subject: [PATCH 69/73] Update plugins/azure/apiManagement/apiInstanceHasTags.js --- plugins/azure/apiManagement/apiInstanceHasTags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.js b/plugins/azure/apiManagement/apiInstanceHasTags.js index a052b4277f..76e47124ad 100644 --- a/plugins/azure/apiManagement/apiInstanceHasTags.js +++ b/plugins/azure/apiManagement/apiInstanceHasTags.js @@ -38,7 +38,7 @@ module.exports = { if (!apiInstance.id) continue; if (apiInstance.tags && Object.entries(apiInstance.tags).length > 0) { - helpers.addResult(results, 0, 'API Management service has tags associated', location, apiInstance.id); + helpers.addResult(results, 0, 'API Management has tags associated', location, apiInstance.id); } else { helpers.addResult(results, 2, 'API Management instance does not have tags associated', location, apiInstance.id); } From 01334969c75e53dd6bb95a8bdcc0d22bacf92a9a Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:31:44 +0500 Subject: [PATCH 70/73] Update plugins/azure/apiManagement/apiInstanceHasTags.js --- plugins/azure/apiManagement/apiInstanceHasTags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure/apiManagement/apiInstanceHasTags.js b/plugins/azure/apiManagement/apiInstanceHasTags.js index 76e47124ad..f1903dcc30 100644 --- a/plugins/azure/apiManagement/apiInstanceHasTags.js +++ b/plugins/azure/apiManagement/apiInstanceHasTags.js @@ -38,7 +38,7 @@ module.exports = { if (!apiInstance.id) continue; if (apiInstance.tags && Object.entries(apiInstance.tags).length > 0) { - helpers.addResult(results, 0, 'API Management has tags associated', location, apiInstance.id); + helpers.addResult(results, 0, 'API Management instance has tags associated', location, apiInstance.id); } else { helpers.addResult(results, 2, 'API Management instance does not have tags associated', location, apiInstance.id); } From 0b63e9ca0d4cf56faa571fc8987a4c97b9222600 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:34:51 +0500 Subject: [PATCH 71/73] Apply suggestions from code review --- .../azure/apiManagement/apiInstanceManagedIdentity.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js index 1d14dcc99e..d9ebd16370 100644 --- a/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js +++ b/plugins/azure/apiManagement/apiInstanceManagedIdentity.spec.js @@ -13,7 +13,7 @@ const apiManagementService = [ "zones": null, "location": "East US", "tags": {}, - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" }, @@ -32,7 +32,7 @@ const apiManagementService = [ "zones": null, "location": "East US", "tags": {}, - "id": "/subscriptions/123456/resourceGroups/fatima-testfunction_group/providers/Microsoft.ApiManagement/service/meerab", + "id": "/subscriptions/123456/resourceGroups/testfunction_group/providers/Microsoft.ApiManagement/service/test", "name": "meerab", "type": "Microsoft.ApiManagement/service" } From b2f302b374fde4b2c7529a987ff5029f6c7bc0a1 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:24:02 +0500 Subject: [PATCH 72/73] Update locations_gov.js --- helpers/azure/locations_gov.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/azure/locations_gov.js b/helpers/azure/locations_gov.js index 5ab4f04fb6..34ea27dda3 100644 --- a/helpers/azure/locations_gov.js +++ b/helpers/azure/locations_gov.js @@ -85,5 +85,5 @@ module.exports = { computeGalleries: locations, databricks: locations, containerApps: locations, - synapse: locations, + synapse: locations }; From e49a1bd46c4f550a7dd9d8080388b6c70da61548 Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Sun, 16 Jun 2024 18:25:13 +0500 Subject: [PATCH 73/73] Update exports.js --- exports.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exports.js b/exports.js index c181076c01..f1e92cdd44 100644 --- a/exports.js +++ b/exports.js @@ -1194,12 +1194,11 @@ module.exports = { 'workspaceManagedServicesCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedServicesCmk.js'), 'workspaceManagedDiskCmk' : require(__dirname + '/plugins/azure/databricks/workspaceManagedDiskCmk.js'), 'workspaceHasTags' : require(__dirname + '/plugins/azure/databricks/workspaceHasTags.js'), - + 'workspaceManagedIdentity' : require(__dirname + '/plugins/azure/synapse/workspaceManagedIdentity.js'), 'synapseWorkspaceAdAuthEnabled' : require(__dirname + '/plugins/azure/synapse/synapseWorkspaceAdAuthEnabled.js'), 'synapseWorkspacPrivateEndpoint': require(__dirname + '/plugins/azure/synapse/synapseWorkspacPrivateEndpoint.js'), - }, github: { 'publicKeysRotated' : require(__dirname + '/plugins/github/users/publicKeysRotated.js'),