From dc8c7a2208b7f5aa2e34eeba314f3295197b6ad0 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 17 Jun 2024 00:42:44 +0500 Subject: [PATCH 1/5] M/Aws/Api-gateway-v2-access-logging --- exports.js | 1 + helpers/aws/api.js | 6 + .../apigateway/apigatewayV2AccessLogging.js | 85 +++++++ .../apigatewayV2AccessLogging.spec.js | 218 ++++++++++++++++++ 4 files changed, 310 insertions(+) create mode 100644 plugins/aws/apigateway/apigatewayV2AccessLogging.js create mode 100644 plugins/aws/apigateway/apigatewayV2AccessLogging.spec.js diff --git a/exports.js b/exports.js index 2f37757420..ecc8da4c92 100644 --- a/exports.js +++ b/exports.js @@ -26,6 +26,7 @@ module.exports = { 'apigatewayDefaultEndpointDisabled' : require(__dirname + '/plugins/aws/apigateway/apigatewayDefaultEndpointDisabled.js'), 'apigatewayAuthorization' : require(__dirname + '/plugins/aws/apigateway/apigatewayAuthorization.js'), 'apigatewayV2Authorization' : require(__dirname + '/plugins/aws/apigateway/apigatewayV2Authorization.js'), + 'apigatewayV2AccessLogging' : require(__dirname + '/plugins/aws/apigateway/apigatewayV2AccessLogging.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 342eb14f72..ec81bc6bc3 100644 --- a/helpers/aws/api.js +++ b/helpers/aws/api.js @@ -1851,6 +1851,12 @@ var postcalls = [ } }, ApiGatewayV2: { + getStages: { + reliesOnService: 'apigatewayv2', + reliesOnCall: 'getApis', + filterKey: 'ApiId', + filterValue: 'ApiId' + }, getAuthorizers: { reliesOnService: 'apigatewayv2', reliesOnCall: 'getApis', diff --git a/plugins/aws/apigateway/apigatewayV2AccessLogging.js b/plugins/aws/apigateway/apigatewayV2AccessLogging.js new file mode 100644 index 0000000000..ab266f4561 --- /dev/null +++ b/plugins/aws/apigateway/apigatewayV2AccessLogging.js @@ -0,0 +1,85 @@ +var async = require('async'); +var helpers = require('../../../helpers/aws'); + +module.exports = { + title: 'API Gateway V2 Authorization', + category: 'API Gateway', + domain: 'Availability', + severity: 'High', + description: 'Ensures that Amazon API Gateway V2 APIs are using authorizer.', + more_info: 'API Gateway V2 APIs should be configured to use authorizer to enforce security measures and restrict access to API to only authorized users or processess.', + recommended_action: 'Modify API Gateway V2 configuration and ensure that appropriate authorizers are set up for each API.', + link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html', + apis: ['ApiGatewayV2:getApis','ApiGatewayV2:getStages'], + realtime_triggers: ['ApiGatewayV2:createApi','ApiGatewayV2:deleteApi','ApiGatewayV2:importApi','ApiGatewayv2:CreateStage','ApiGatewayv2:UpdateStage','ApiGatewayv2:DeleteStage'], + + run: function(cache, settings, callback) { + var results = []; + var source = {}; + var regions = helpers.regions(settings); + var awsOrGov = helpers.defaultPartition(settings); + + async.each(regions.apigatewayv2, function(region, rcb){ + var getApis = helpers.addSource(cache, source, + ['apigatewayv2', 'getApis', region]); + + if (!getApis) return rcb(); + + if (getApis.err || !getApis.data) { + helpers.addResult(results, 3, + `Unable to query for API Gateway V2 APIs: ${helpers.addError(getApis)}`, region); + return rcb(); + } + + if (!getApis.data.length) { + helpers.addResult(results, 0, 'No API Gateway V2 APIs found', region); + return rcb(); + } + + getApis.data.forEach(api => { + if (!api.ApiId) return; + + var apiArn = `arn:${awsOrGov}:apigateway:${region}::/apis/${api.ApiId}`; + + var getStages = helpers.addSource(cache, source, + ['apigatewayv2', 'getStages', region, api.ApiId]); + + if (!getStages || getStages.err || !getStages.data || !getStages.data.Items) { + helpers.addResult(results, 3, + `Unable to query for API Gateway V2 API Stages: ${helpers.addError(getStages)}`, + region, apiArn); + return; + } + + if (!getStages.data.Items.length) { + helpers.addResult(results, 0, + 'No API Gateway V2 API Stages found', + region, apiArn); + return; + } + + getStages.data.Items.forEach(stage => { + if (!stage.StageName) return; + + var stageArn = `arn:${awsOrGov}:apigateway:${region}::/apis/${api.ApiId}/stages/${stage.StageName}`; + if (stage.AccessLogSetting) { + helpers.addResult(results, 0, + 'API Gateway V2 API stage has access logging enabled', + region, stageArn); + } else { + helpers.addResult(results, 2, + 'API Gateway V2 API stage does not have access logging enabled', + region, stageArn); + } + }); + + }); + + rcb(); + }, function() { + callback(null, results, source); + }); + } +}; + + \ No newline at end of file diff --git a/plugins/aws/apigateway/apigatewayV2AccessLogging.spec.js b/plugins/aws/apigateway/apigatewayV2AccessLogging.spec.js new file mode 100644 index 0000000000..f6dd1a6cc1 --- /dev/null +++ b/plugins/aws/apigateway/apigatewayV2AccessLogging.spec.js @@ -0,0 +1,218 @@ +var expect = require('chai').expect; +var apigatewayV2AccessLogging = require('./apigatewayV2AccessLogging'); + +const createCache = (getApis, getStages) => { + if (getApis && getApis.length && getApis[0].ApiId) var restApiId = getApis[0].ApiId; + return { + apigatewayv2: { + getApis: { + 'us-east-1': { + data: getApis + } + }, + getStages: { + 'us-east-1': { + [restApiId]: { + data: { + Items: getStages + } + } + } + } + } + }; +}; + +const createErrorCache = () => { + return { + apigatewayv2: { + getApis: { + 'us-east-1': { + err: { + message: 'error fetching API Gateway v2 APIs' + }, + }, + }, + getStages: { + 'us-east-1': { + err: { + message: 'error fetching API Gateway v2 stages' + }, + }, + } + + }, + }; +}; + +const createUnknownForStage = (api) => { + return { + apigatewayv2: { + getApis: { + 'us-east-1': { + data: api + } + }, + getStages: { + 'us-east-1': 'err' + } + } + }; +}; + +describe('apigatewayV2AccessLogging', function () { + describe('run', function () { + it('should return UNKNOWN if unable to query for API Gateway v2 APIs', function (done) { + const cache = createErrorCache(); + apigatewayV2AccessLogging.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 V2 APIs:'); + done(); + }); + }); + + it('should return PASS if no API Gateway Rest APIs found', function (done) { + const cache = createCache([]); + apigatewayV2AccessLogging.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 V2 APIs found'); + done(); + }); + }); + + it('should return PASS if no stages found', function (done) { + const getApis = [ + { + ApiId: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + const getStages = []; + const cache = createCache(getApis, getStages); + apigatewayV2AccessLogging.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 V2 API Stages found'); + done(); + }); + }); + + it('should return PASS if Api gateway v2 stage has access logging enabled', function (done) { + const getApis = [ + { + ApiId: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + const getStages = [ + { + "AutoDeploy": true, + "CreatedDate": "2023-12-11T20:07:28.000Z", + "DefaultRouteSettings": { + "DetailedMetricsEnabled": false + }, + "DeploymentId": "biw5qf", + "Description": "Created by AWS Lambda", + "LastDeploymentStatusMessage": "Successfully deployed stage with deployment ID 'biw5qf'", + "LastUpdatedDate": "2023-12-11T20:07:29.000Z", + "RouteSettings": {}, + "StageName": "default", + "StageVariables": {}, + "Tags": {}, + "AccessLogSetting": { + "LogArn": "arn:aws:1234:log" + } + } + ]; + const cache = createCache(getApis, getStages); + apigatewayV2AccessLogging.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('API Gateway V2 API stage has access logging enabled') + done(); + }); + }); + + it('should return PASS if Api gateway v2 stage has access logging enabled', function (done) { + const getApis = [ + { + ApiId: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + const getStages = [ + { + "AutoDeploy": true, + "CreatedDate": "2023-12-11T20:07:28.000Z", + "DefaultRouteSettings": { + "DetailedMetricsEnabled": false + }, + "DeploymentId": "biw5qf", + "Description": "Created by AWS Lambda", + "LastDeploymentStatusMessage": "Successfully deployed stage with deployment ID 'biw5qf'", + "LastUpdatedDate": "2023-12-11T20:07:29.000Z", + "RouteSettings": {}, + "StageName": "default", + "StageVariables": {}, + "Tags": {}, + } + ]; + const cache = createCache(getApis, getStages); + apigatewayV2AccessLogging.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('API Gateway V2 API stage does not have access logging enabled') + done(); + }); + }); + + it('should return UNKNOWN if unable to query for api stages', function (done) { + const getApis = [ + { + ApiId: 'api-id', + name: 'TestAPI', + description: 'Test API', + createdDate: 1621916018, + apiKeySource: 'HEADER', + endpointConfiguration: { + types: ['REGIONAL'] + } + } + ]; + + const cache = createUnknownForStage(getApis); + apigatewayV2AccessLogging.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 V2 API Stages:') + done(); + }); + }); + }); +}); From 167c1e3769d03df25fa1f30f0c192c5152084079 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Mon, 17 Jun 2024 01:00:27 +0500 Subject: [PATCH 2/5] plugins/aws/apigateway/apigatewayV2AccessLogging.js --- plugins/aws/apigateway/apigatewayV2AccessLogging.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/aws/apigateway/apigatewayV2AccessLogging.js b/plugins/aws/apigateway/apigatewayV2AccessLogging.js index ab266f4561..355a8999f6 100644 --- a/plugins/aws/apigateway/apigatewayV2AccessLogging.js +++ b/plugins/aws/apigateway/apigatewayV2AccessLogging.js @@ -2,17 +2,17 @@ var async = require('async'); var helpers = require('../../../helpers/aws'); module.exports = { - title: 'API Gateway V2 Authorization', + title: 'API Gateway V2 Access Logging', category: 'API Gateway', domain: 'Availability', severity: 'High', - description: 'Ensures that Amazon API Gateway V2 APIs are using authorizer.', - more_info: 'API Gateway V2 APIs should be configured to use authorizer to enforce security measures and restrict access to API to only authorized users or processess.', - recommended_action: 'Modify API Gateway V2 configuration and ensure that appropriate authorizers are set up for each API.', - link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html', + description: 'Ensures that Amazon API Gateway V2 APIs stages have access logging enabled.', + more_info: 'API Gateway V2 access logs provide detailed information about APIs and how the caller accessed the API. These logs are useful for applications for security and access audits which helps to analyze traffic patterns and to troubleshoot issues.', + recommended_action: 'Modify API Gateway V2 configuration and ensure that access logging is configured for each stage.', + link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-logging.html', apis: ['ApiGatewayV2:getApis','ApiGatewayV2:getStages'], realtime_triggers: ['ApiGatewayV2:createApi','ApiGatewayV2:deleteApi','ApiGatewayV2:importApi','ApiGatewayv2:CreateStage','ApiGatewayv2:UpdateStage','ApiGatewayv2:DeleteStage'], - + run: function(cache, settings, callback) { var results = []; var source = {}; From fbd754a34200d03aa430f9c1f256be4d8f2e839e Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Mon, 17 Jun 2024 01:01:38 +0500 Subject: [PATCH 3/5] Update plugins/aws/apigateway/apigatewayV2AccessLogging.js --- plugins/aws/apigateway/apigatewayV2AccessLogging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/aws/apigateway/apigatewayV2AccessLogging.js b/plugins/aws/apigateway/apigatewayV2AccessLogging.js index 355a8999f6..fbe471c135 100644 --- a/plugins/aws/apigateway/apigatewayV2AccessLogging.js +++ b/plugins/aws/apigateway/apigatewayV2AccessLogging.js @@ -5,7 +5,7 @@ module.exports = { title: 'API Gateway V2 Access Logging', category: 'API Gateway', domain: 'Availability', - severity: 'High', + severity: 'Medium', description: 'Ensures that Amazon API Gateway V2 APIs stages have access logging enabled.', more_info: 'API Gateway V2 access logs provide detailed information about APIs and how the caller accessed the API. These logs are useful for applications for security and access audits which helps to analyze traffic patterns and to troubleshoot issues.', recommended_action: 'Modify API Gateway V2 configuration and ensure that access logging is configured for each stage.', From 888962dde3e99e9a383c028b13656202691a7f6e Mon Sep 17 00:00:00 2001 From: alphadev4 <113519745+alphadev4@users.noreply.github.com> Date: Wed, 19 Jun 2024 23:27:20 +0500 Subject: [PATCH 4/5] Apply suggestions from code review --- plugins/aws/apigateway/apigatewayV2AccessLogging.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/aws/apigateway/apigatewayV2AccessLogging.js b/plugins/aws/apigateway/apigatewayV2AccessLogging.js index fbe471c135..bf5b107d83 100644 --- a/plugins/aws/apigateway/apigatewayV2AccessLogging.js +++ b/plugins/aws/apigateway/apigatewayV2AccessLogging.js @@ -6,8 +6,8 @@ module.exports = { category: 'API Gateway', domain: 'Availability', severity: 'Medium', - description: 'Ensures that Amazon API Gateway V2 APIs stages have access logging enabled.', - more_info: 'API Gateway V2 access logs provide detailed information about APIs and how the caller accessed the API. These logs are useful for applications for security and access audits which helps to analyze traffic patterns and to troubleshoot issues.', + description: 'Ensures that Amazon API Gateway V2 API stages have access logging enabled.', + more_info: 'API Gateway V2 access logs provide detailed information about APIs and how the caller accessed the API. These logs are useful for security and access audits which helps to analyze traffic patterns and troubleshoot issues.', recommended_action: 'Modify API Gateway V2 configuration and ensure that access logging is configured for each stage.', link: 'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-logging.html', apis: ['ApiGatewayV2:getApis','ApiGatewayV2:getStages'], From b1358163875e250d9811b2c2f53a92fc03cecaa8 Mon Sep 17 00:00:00 2001 From: AkhtarAmir Date: Wed, 19 Jun 2024 23:44:12 +0500 Subject: [PATCH 5/5] Added china region --- helpers/aws/regions_china.js | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/aws/regions_china.js b/helpers/aws/regions_china.js index b3d5984374..5a7e38a712 100644 --- a/helpers/aws/regions_china.js +++ b/helpers/aws/regions_china.js @@ -13,6 +13,7 @@ module.exports = { cognitoidentityserviceprovider: regions, acm: [], apigateway: regions, + apigatewayv2: regions, athena: [], bedrock:[], cloudfront: [],