Skip to content

Commit 735ba19

Browse files
committed
Read config from local json files to not be dependant on S3 rate limits during an attack
1 parent 7392dd4 commit 735ba19

File tree

3 files changed

+31
-100
lines changed

3 files changed

+31
-100
lines changed

templates/validator.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""
22
Validator stack.
33
"""
4-
from troposphere import Template, constants, Parameter, awslambda, Ref, Output, GetAtt
4+
from troposphere import Template, constants, Parameter, awslambda, Ref, Output
55

66
import custom_resources.awslambda
7-
import custom_resources.cloudformation
87
import cfnutils.output
98

109

@@ -36,31 +35,15 @@
3635
))
3736
template.set_parameter_label(param_s3_key, "Lambda S3 key")
3837

39-
param_config_bucket = template.add_parameter(Parameter(
40-
"ConfigBucket",
41-
Default="",
42-
Type=constants.STRING,
43-
Description="Name of the configuration bucket",
44-
))
45-
template.set_parameter_label(param_config_bucket, "Lambda Config S3 bucket")
46-
47-
cloudformation_tags = template.add_resource(custom_resources.cloudformation.Tags(
48-
"CfnTags",
49-
Set={
50-
'ConfigBucket': Ref(param_config_bucket),
51-
},
52-
))
53-
5438
validator_lambda = template.add_resource(awslambda.Function(
5539
"ValidatorLambda",
5640
Code=awslambda.Code(
5741
S3Bucket=Ref(param_s3_bucket_name),
5842
S3Key=Ref(param_s3_key),
5943
),
60-
Runtime='nodejs14.x',
44+
Runtime='nodejs22.x',
6145
Handler='index.handler',
6246
Role=Ref(param_role),
63-
Tags=GetAtt(cloudformation_tags, 'TagList'),
6447
))
6548

6649
validator_version = template.add_resource(custom_resources.awslambda.Version(

λ@E/config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"parameter_store_region": "eu-west-1",
3+
"parameter_store_parameter_name": "/authorizer/jwt-secret",
4+
"set_cookie_path": "/auth-89CE3FEF-FCF6-43B3-9DBA-7C410CAAE220/set-cookie",
5+
"cookie_name_access_token": "authorizer_access",
6+
"cookie_name_no_redirect": "authorizer_no_redirect",
7+
"authorize_url": "https://authorizer.example.org/authorize"
8+
}

λ@E/index.js

Lines changed: 21 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -12,77 +12,20 @@
1212
"use strict";
1313

1414
const JWT = require('jsonwebtoken');
15-
const AWS = require('aws-sdk');
15+
const { SSMClient, GetParameterCommand } = require('@aws-sdk/client-ssm');const fs = require('fs')
1616
const querystring = require('querystring');
1717
const url = require('url');
1818

1919

20-
function asyncLambdaGetFunction(param, service_param = {}) {
21-
// Async wrapper around the Lambda GetFunction API call
22-
return new Promise(function(resolve, reject) {
23-
const lambda = new AWS.Lambda(service_param);
24-
lambda.getFunction(param, function(err, data) {
25-
if(err !== null) { reject(err); }
26-
else { resolve(data); }
27-
});
28-
});
29-
}
30-
31-
function asyncS3GetObject(param) {
32-
// Async wrapper around the S3 GetObject API call
33-
return new Promise(function(resolve, reject) {
34-
const s3 = new AWS.S3();
35-
s3.getObject(param, function(err, data) {
36-
if(err !== null) { reject(err); }
37-
else { resolve(data); }
38-
});
39-
});
40-
}
41-
42-
async function get_config_bucket(context) {
43-
/* Lambda@Edge does not support environment parameters.
44-
* We use Tags as workaround. This function gets the value of the tag.
45-
*/
46-
const dot_location = context.functionName.indexOf('.');
47-
const functionName_without_region = context.functionName.substring(dot_location + 1);
48-
const lambda_description = await asyncLambdaGetFunction({
49-
'FunctionName': functionName_without_region,
50-
}, {
51-
region: 'us-east-1', // Lambda@Edge is always us-east-1
52-
}
53-
);
54-
return lambda_description.Tags['ConfigBucket'];
55-
}
5620
async function get_config_(context) {
57-
let config = { // Default settings, keep in sync with Lambda-code!
58-
'function_arn': context['invokedFunctionArn'],
59-
60-
'parameter_store_region': 'eu-west-1',
61-
'parameter_store_parameter_name': '/authorizer/jwt-secret',
62-
63-
'set_cookie_path': '/auth-89CE3FEF-FCF6-43B3-9DBA-7C410CAAE220/set-cookie',
64-
'cookie_name_access_token': 'authorizer_access',
65-
'cookie_name_no_redirect': 'authorizer_no_redirect',
66-
67-
'authorize_url': 'https://authorizer.example.org/authorize',
21+
const accountId = context.invokedFunctionArn.split(':')[4];
22+
const accountSpecificConfigPath = `./config-${accountId}.json`;
23+
let config = require('./config.json');
24+
if(fs.existsSync(accountSpecificConfigPath)) {
25+
let accountSpecificConfig = require(accountSpecificConfigPath);
26+
config = { ...config, ...accountSpecificConfig};
6827
};
69-
const config_bucket = await get_config_bucket(context);
70-
try {
71-
const config_response = await asyncS3GetObject({
72-
'Bucket': config_bucket,
73-
'Key': 'config.json',
74-
});
75-
const body = config_response.Body.toString('utf-8');
76-
console.log("Retrieved config from S3:");
77-
console.log(body);
78-
const parsed_body = JSON.parse(body);
79-
for(let key in parsed_body) {
80-
config[key] = parsed_body[key];
81-
}
82-
} catch(e) {
83-
console.log("Could not retrieve config from S3. Using defaults.");
84-
console.log(e);
85-
}
28+
config['function_arn'] = context['invokedFunctionArn'];
8629
return config;
8730
}
8831
function get_config_promise(context) {
@@ -92,22 +35,19 @@ function get_config_promise(context) {
9235
return get_config_promise.cache
9336
}
9437

95-
function get_jwt_secret_promise(region, param_name) {
96-
if(typeof get_jwt_secret_promise.cache === 'undefined') {
97-
get_jwt_secret_promise.cache = new Promise(function(resolve, reject) {
98-
const ssm = new AWS.SSM({
99-
'region': region,
100-
});
101-
ssm.getParameter({
102-
'Name': param_name,
103-
'WithDecryption': true,
104-
},
105-
function(err, data) {
106-
if(err !== null) { reject(err); }
107-
else { resolve(data['Parameter']['Value']); }
108-
}
109-
);
110-
});
38+
async function getSSMParameter(parameter_name, parameter_region) {
39+
const client = new SSMClient({ region: parameter_region });
40+
const command = new GetParameterCommand({
41+
Name: parameter_name,
42+
WithDecryption: true,
43+
});
44+
const response = await client.send(command);
45+
return response.Parameter.Value;
46+
}
47+
48+
async function get_jwt_secret_promise(region, param_name) {
49+
if (typeof get_jwt_secret_promise.cache === 'undefined') {
50+
get_jwt_secret_promise.cache = await getSSMParameter(param_name, region)
11151
}
11252
return get_jwt_secret_promise.cache;
11353
}

0 commit comments

Comments
 (0)