Skip to content

Commit 638c445

Browse files
authoredOct 14, 2020
feat(ratelimit): add rate limiting (#2245)
1 parent 3363064 commit 638c445

24 files changed

+145
-3
lines changed
 

‎config/custom-environment-variables.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,7 @@ build:
399399
__name: CLUSTER_ENVIRONMENT_VARIABLES
400400
__format: json
401401
externalJoin: EXTERNAL_JOIN
402+
403+
rateLimit:
404+
__name: RATE_LIMIT_VARIABLES
405+
__format: json

‎config/default.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,11 @@ build:
305305
environment:
306306
SD_VERSION: 4
307307
externalJoin: false
308+
309+
rateLimit:
310+
# set true to enable rate limiting on auth token
311+
enabled: false
312+
# max request limit on auth token per duration, default: 300 (1 rps)
313+
limit: 300
314+
# limit duration in milliseconds, default: 300000 (5 mins)
315+
duration: 300000

‎lib/registerPlugins.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ async function registerDefaultPlugins(server) {
2121
'../plugins/template-validator',
2222
'../plugins/command-validator',
2323
'../plugins/promster',
24-
'../plugins/metrics'
24+
'../plugins/metrics',
25+
'../plugins/ratelimit'
2526
].map(plugin => require(plugin));
2627

2728
return plugins.map(async pluginObj =>

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"deepmerge": "^4.2.2",
8686
"hapi-auth-bearer-token": "^6.1.6",
8787
"hapi-auth-jwt2": "^10.1.0",
88+
"hapi-rate-limit": "^5.0.0",
8889
"hapi-swagger": "^14.0.0",
8990
"joi": "^17.2.0",
9091
"js-yaml": "^3.13.1",

‎plugins/auth/contexts.js

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ module.exports = config => ({
1616
description: 'Get all auth contexts',
1717
notes: 'Get all auth contexts',
1818
tags: ['api', 'auth', 'context'],
19+
plugins: {
20+
'hapi-rate-limit': {
21+
enabled: false
22+
}
23+
},
1924
handler: async (request, h) => {
2025
const { scm } = request.server.app.userFactory;
2126
const scmContexts = scm.getScmContexts();

‎plugins/auth/crumb.js

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ module.exports = () => ({
1414
description: 'Generate crumb',
1515
notes: 'Should return a crumb',
1616
tags: ['api', 'crumb', 'auth'],
17+
plugins: {
18+
'hapi-rate-limit': {
19+
enabled: false
20+
}
21+
},
1722
handler: async (request, h) =>
1823
h.response({
1924
crumb: request.server.plugins.crumb.generate(request, h)

‎plugins/auth/key.js

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ module.exports = options => ({
1616
description: 'Get jwt public key',
1717
notes: 'Public Key for verifying JSON Web Tokens',
1818
tags: ['api', 'auth', 'key'],
19+
plugins: {
20+
'hapi-rate-limit': {
21+
enabled: false
22+
}
23+
},
1924
handler: async (request, h) =>
2025
h.response({
2126
key: options.jwtPublicKey

‎plugins/auth/login.js

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ function addGuestRoute(config) {
1919
description: 'Login as an guest user',
2020
notes: 'Authenticate an guest user',
2121
tags: ['api', 'auth', 'login'],
22+
plugins: {
23+
'hapi-rate-limit': {
24+
enabled: false
25+
}
26+
},
2227
auth: null,
2328
handler: async (request, h) => {
2429
// Check if guest is allowed to login

‎plugins/auth/token.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ module.exports = () => ({
2020
scope: ['user', 'pipeline']
2121
},
2222
plugins: {
23-
'hapi-swagger': { security: [{ token: [] }] }
23+
'hapi-swagger': { security: [{ token: [] }] },
24+
'hapi-rate-limit': {
25+
enabled: false
26+
}
2427
},
2528
handler: async (request, h) => {
2629
let profile = request.auth.credentials;

‎plugins/banners/get.js

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ module.exports = () => ({
1313
description: 'Get a single banner',
1414
notes: 'Return a banner record',
1515
tags: ['api', 'banners'],
16+
plugins: {
17+
'hapi-rate-limit': {
18+
enabled: false
19+
}
20+
},
1621
handler: async (request, h) => {
1722
const { bannerFactory } = request.server.app;
1823
const { id } = request.params;

‎plugins/banners/list.js

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ module.exports = () => ({
1010
description: 'Get banners',
1111
notes: 'Returns all banner records',
1212
tags: ['api', 'banners'],
13+
plugins: {
14+
'hapi-rate-limit': {
15+
enabled: false
16+
}
17+
},
1318
handler: async (request, h) => {
1419
const { bannerFactory } = request.server.app;
1520

‎plugins/command-validator.js

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const commandValidatorPlugin = {
2222
description: 'Validate a given sd-command.yaml',
2323
notes: 'returns the parsed config, validation errors, or both',
2424
tags: ['api', 'validation', 'yaml'],
25+
plugins: {
26+
'hapi-rate-limit': {
27+
enabled: false
28+
}
29+
},
2530
handler: async (request, h) => {
2631
try {
2732
const commandString = request.payload.yaml;

‎plugins/metrics.js

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ module.exports = {
1818
path: '/metrics',
1919
handler: (_, h) => h.response(getSummary()),
2020
config: {
21+
plugins: {
22+
'hapi-rate-limit': {
23+
enabled: false
24+
}
25+
},
2126
description: 'application metrics',
2227
notes: 'Expose application metrics',
2328
tags: ['api']

‎plugins/pipelines/badge.js

+5
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ module.exports = config => ({
8383
description: 'Get a badge for the pipeline',
8484
notes: 'Redirects to the badge service',
8585
tags: ['api', 'pipelines', 'badge'],
86+
plugins: {
87+
'hapi-rate-limit': {
88+
enabled: false
89+
}
90+
},
8691
handler: async (request, h) => {
8792
const factory = request.server.app.pipelineFactory;
8893
const badgeService = request.server.app.ecosystem.badges;

‎plugins/pipelines/jobBadge.js

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ module.exports = config => ({
3838
description: 'Get a badge for a job',
3939
notes: 'Redirects to the badge service',
4040
tags: ['api', 'job', 'badge'],
41+
plugins: {
42+
'hapi-rate-limit': {
43+
enabled: false
44+
}
45+
},
4146
handler: async (request, h) => {
4247
const { jobFactory } = request.server.app;
4348
const { pipelineFactory } = request.server.app;

‎plugins/ratelimit.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const rateLimit = require('hapi-rate-limit');
4+
const config = require('config');
5+
const rateLimitConfig = config.get('rateLimit');
6+
7+
module.exports = {
8+
name: 'ratelimit',
9+
async register(server) {
10+
server.ext('onPreAuth', async (request, h) => {
11+
// see https://github.com/glennjones/hapi-swagger/issues/623
12+
if (request.path.startsWith('/v4/swagger')) {
13+
request.route.settings.plugins['hapi-rate-limit'] = {
14+
enabled: false
15+
};
16+
}
17+
18+
return h.continue;
19+
});
20+
21+
await server.register({
22+
plugin: rateLimit,
23+
options: {
24+
enabled: rateLimitConfig.enabled || false,
25+
userLimit: rateLimitConfig.limit,
26+
userAttribute: 'jti',
27+
userCache: {
28+
expiresIn: rateLimitConfig.duration
29+
},
30+
authLimit: false,
31+
headers: false,
32+
pathLimit: false,
33+
userPathLimit: false,
34+
trustProxy: true
35+
}
36+
});
37+
}
38+
};

‎plugins/stats.js

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const statsPlugin = {
2222
description: 'API stats',
2323
notes: 'Should return statistics for the entire system',
2424
tags: ['api', 'stats'],
25+
plugins: {
26+
'hapi-rate-limit': {
27+
enabled: false
28+
}
29+
},
2530
response: {
2631
schema: schema.api.stats
2732
}

‎plugins/status.js

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const statusPlugin = {
1919
description: 'API status',
2020
notes: 'Should respond with 200: ok',
2121
tags: ['api'],
22+
plugins: {
23+
'hapi-rate-limit': {
24+
enabled: false
25+
}
26+
},
2227
response: {
2328
schema: schema.api.status
2429
}

‎plugins/swagger.js

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ const swaggerPlugin = {
1818
name: 'X-Token',
1919
in: 'header'
2020
}
21+
},
22+
// see https://github.com/glennjones/hapi-swagger/blob/master/optionsreference.md#json-json-endpoint-needed-to-create-ui
23+
documentationRoutePlugins: {
24+
'hapi-rate-limit': {
25+
enabled: false
26+
}
2127
}
2228
},
2329
security: [{ token: [] }]

‎plugins/template-validator.js

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const templateValidatorPlugin = {
2323
description: 'Validate a given sd-template.yaml',
2424
notes: 'returns the parsed config, validation errors, or both',
2525
tags: ['api', 'validation', 'yaml'],
26+
plugins: {
27+
'hapi-rate-limit': {
28+
enabled: false
29+
}
30+
},
2631
handler: async (request, h) => {
2732
try {
2833
const templateString = request.payload.yaml;

‎plugins/validator.js

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const validatorTemplate = {
2222
description: 'Validate a given screwdriver.yaml',
2323
notes: 'Returns the parsed config or validation errors',
2424
tags: ['api', 'validation', 'yaml'],
25+
plugins: {
26+
'hapi-rate-limit': {
27+
enabled: false
28+
}
29+
},
2530
handler: async (request, h) =>
2631
parser(
2732
request.payload.yaml,

‎plugins/versions.js

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ const versionsTemplate = {
5858
description: 'API Package Versions',
5959
notes: 'Returns list of Screwdriver package versions and third-party dependencies',
6060
tags: ['api'],
61+
plugins: {
62+
'hapi-rate-limit': {
63+
enabled: false
64+
}
65+
},
6166
response: {
6267
schema: schema.api.versions
6368
}

‎plugins/webhooks/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,11 @@ const webhooksPlugin = {
11121112
description: 'Handle webhook events',
11131113
notes: 'Acts on pull request, pushes, comments, etc.',
11141114
tags: ['api', 'webhook'],
1115+
plugins: {
1116+
'hapi-rate-limit': {
1117+
enabled: false
1118+
}
1119+
},
11151120
payload: {
11161121
maxBytes: parseInt(pluginOptions.maxBytes, 10) || DEFAULT_MAX_BYTES
11171122
},

‎test/lib/registerPlugins.test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ describe('Register Unit Test Case', () => {
1818
'../plugins/template-validator',
1919
'../plugins/command-validator',
2020
'../plugins/promster',
21-
'../plugins/metrics'
21+
'../plugins/metrics',
22+
'../plugins/ratelimit'
2223
];
2324
const resourcePlugins = [
2425
'../plugins/auth',

0 commit comments

Comments
 (0)
Please sign in to comment.