Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update secrets manager with throwOnFailedCall flag #236

Merged
merged 6 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ Currently available middlewares:
- [`http-security-headers`](/packages/http-security-headers): Applies best practice security headers to responses. It's a simplified port of HelmetJS.
- [`http-urlencode-body-parser`](/packages/http-urlencode-body-parser): Automatically parses HTTP requests with URL encoded body (typically the result of a form submit).
- [`s3-key-normalizer`](/packages/s3-key-normalizer): Normalizes key names in s3 events.
- [`secrets-manager`](/packages/secrets-manager): Fetches parameters from [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html).
- [`ssm`](/packages/ssm): Fetches parameters from [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html).
- [`validator`](/packages/validator): Automatically validates incoming events and outgoing responses against custom schemas
- [`warmup`](/packages/warmup): Warmup middleware that helps to reduce the [cold-start issue](https://serverless.com/blog/keep-your-lambdas-warm/)
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"packages": [
"packages/*"
],
"version": "1.0.0-alpha.16"
"version": "1.0.0-alpha.17"
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "middy-monorepo",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/cache/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/cache",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Cache middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/core",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (core package)",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/do-not-wait-for-empty-event-loop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/do-not-wait-for-empty-event-loop",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Middleware for the middy framework that allows to easily disable the wait for empty event loop in a Lambda function",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/error-logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/error-logger",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Input and output logger middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-content-negotiation/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-content-negotiation",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http content negotiation middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-cors/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-cors",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "CORS (Cross-Origin Resource Sharing) middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-error-handler/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-error-handler",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http error handler middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-event-normalizer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-event-normalizer",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http event normalizer middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-header-normalizer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-header-normalizer",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http header normalizer middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-json-body-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-json-body-parser",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http JSON body parser middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-partial-response/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-partial-response",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Http partial response middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-security-headers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-security-header",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/http-urlencode-body-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/http-urlencode-body-parser",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Urlencode body parser middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/input-output-logger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/input-output-logger",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Input and output logger middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/s3-key-normalizer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/s3-key-normalizer",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "S3 key normalizer middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
1 change: 1 addition & 0 deletions packages/secrets-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ npm install --save @middy/secrets-manager
- `secrets` (object) : Map of secrets to fetch from Secrets Manager, where the key is the destination, and value is secret name in Secrets Manager.
Example: `{secrets: {RDS_LOGIN: 'dev/rds_login'}}`
- `awsSdkOptions` (object) (optional): Options to pass to AWS.SecretsManager class constructor.
- `throwOnFailedCall` (boolean) (optional): Defaults to `false`. Set it to `true` if you want your lambda to fail in case call to AWS Secrets Manager fails (secrets don't exist or internal error). It will only print error if secrets are already cached.

NOTES:
* Lambda is required to have IAM permission for `secretsmanager:GetSecretValue` action
Expand Down
89 changes: 88 additions & 1 deletion packages/secrets-manager/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('🔒 SecretsManager Middleware', () => {
promise = promise.then(() => {
return new Promise((resolve, reject) => {
handler(event, context, (error, response) => {
if (error) return reject(error)
try {
cb(error, { event, context, response })
resolve()
Expand All @@ -68,7 +69,7 @@ describe('🔒 SecretsManager Middleware', () => {
}
})
})
promise.then(done).catch(err => done(err))
promise.then(done).catch(done)
}

test(`It should set secrets to context`, (done) => {
Expand Down Expand Up @@ -217,6 +218,92 @@ describe('🔒 SecretsManager Middleware', () => {
})
})

test(`It should fail if "throwOnFailedCall" flag provided and call failed`, (done) => {
const errorMessage = 'Internal Error / Secret doesn\'t exist'
getSecretValueMock.mockReturnValueOnce({
promise: () => Promise.reject(new Error(errorMessage))
})

const errHandler = err => {
getSecretValueMock.mockClear()
expect(err.message).toEqual(errorMessage)
done()
}
return testScenario({
mockResponse: {},
middlewareOptions: {
secrets: {
KEY_NAME: 'failed_call'
},
throwOnFailedCall: true
},
callbacks: [
() => {
throw new Error('Not supposed to be called')
}
],
done: errHandler
})
})

test(`It should resolve if "throwOnFailedCall" flag not provided and call failed`, (done) => {
const errorMessage = 'Internal Error / Secret doesn\'t exist'
getSecretValueMock.mockReturnValueOnce({
promise: () => Promise.reject(new Error(errorMessage))
})
return testScenario({
mockResponse: {},
middlewareOptions: {
secrets: {
KEY_NAME: 'failed_call'
}
},
callbacks: [
() => {
expect(getSecretValueMock).toBeCalled()
getSecretValueMock.mockClear()
}
],
done
})
})

test(`It should resolve if "throwOnFailedCall" flag provided but item already cached`, (done) => {
const errorMessage = 'Internal Error / Secret doesn\'t exist'
return testScenario({
mockResponse: {
SecretString: JSON.stringify({ Username: 'username', Password: 'password' })
},
middlewareOptions: {
secrets: {
KEY_NAME: 'rds_key'
},
throwOnFailedCall: true
},
callbacks: [
// invocation 1: fetched
(_, { context }) => {
hasRDSLogin(context)
expect(getSecretValueMock).toBeCalled()

getSecretValueMock.mockClear()

// set up next attempt to fail
getSecretValueMock.mockReturnValueOnce({
promise: () => Promise.reject(new Error(errorMessage))
})
},
// invocation 2: failed but content taken from cache
(_, { context }) => {
hasRDSLogin(context)
expect(getSecretValueMock).toBeCalled()
getSecretValueMock.mockClear()
}
],
done
})
})

test(`It should only refresh once per cache expiry window`, (done) => {
// with cache expiry of 50ms, test what happens when one refresh fails, and
// that the middleware doesn't retry for another 50ms
Expand Down
1 change: 1 addition & 0 deletions packages/secrets-manager/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface ISecretsManagerOptions {
cacheExpiryInMillis?: number;
secrets?: { [key: string]: string; };
awsSdkOptions?: Partial<SecretsManager.Types.ClientConfiguration>;
throwOnFailedCall?: boolean;
}

declare function secretsManager(opts?: ISecretsManagerOptions): middy.IMiddyMiddlewareObject;
5 changes: 5 additions & 0 deletions packages/secrets-manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = opts => {
const defaults = {
awsSdkOptions: {},
secrets: {}, // e.g. { RDS_SECRET: 'dev/rds_login', API_SECRET: '...' }
throwOnFailedCall: false,
cache: false,
cacheExpiryInMillis: undefined,
secretsLoaded: false,
Expand Down Expand Up @@ -54,6 +55,10 @@ module.exports = opts => {
})
.catch(err => {
console.error('failed to refresh secrets from Secrets Manager:', err.message)
// throw error if there is no secret in cache already and flag throwOnFailedCall provided
if (options.throwOnFailedCall && !options.secretsCache) {
throw err
}
// if we already have a cached secrets, then reset the timestamp so we don't
// keep retrying on every invocation which can cause performance problems
// when there's temporary problems with Secrets Manager
Expand Down
2 changes: 1 addition & 1 deletion packages/secrets-manager/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/secrets-manager",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Secrets Manager middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/ssm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/ssm",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "SSM (EC2 Systems Manager) parameters middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/validator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/validator",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Validator middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down
2 changes: 1 addition & 1 deletion packages/warmup/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@middy/warmup",
"version": "1.0.0-alpha.16",
"version": "1.0.0-alpha.17",
"description": "Warmup (cold start mitigation) middleware for the middy framework",
"engines": {
"node": ">=6.10"
Expand Down