Skip to content

Commit

Permalink
M/Aws/Api-gateway-v2-access-logging
Browse files Browse the repository at this point in the history
  • Loading branch information
AkhtarAmir authored and AkhtarAmir committed Jun 16, 2024
1 parent 8411f25 commit dc8c7a2
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 0 deletions.
1 change: 1 addition & 0 deletions exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
6 changes: 6 additions & 0 deletions helpers/aws/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,12 @@ var postcalls = [
}
},
ApiGatewayV2: {
getStages: {
reliesOnService: 'apigatewayv2',
reliesOnCall: 'getApis',
filterKey: 'ApiId',
filterValue: 'ApiId'
},
getAuthorizers: {
reliesOnService: 'apigatewayv2',
reliesOnCall: 'getApis',
Expand Down
85 changes: 85 additions & 0 deletions plugins/aws/apigateway/apigatewayV2AccessLogging.js
Original file line number Diff line number Diff line change
@@ -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);
});
}
};


218 changes: 218 additions & 0 deletions plugins/aws/apigateway/apigatewayV2AccessLogging.spec.js
Original file line number Diff line number Diff line change
@@ -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();
});
});
});
});

0 comments on commit dc8c7a2

Please sign in to comment.