ssm-extension

Fetches values from AWS Systems Manager Parameter Store using the AWS Parameters and Secrets Lambda Extension. The extension runs as a Lambda layer and exposes a local HTTP server (port 2773), so no AWS SDK is required and latency is lower than direct API calls.

Use this middleware instead of @middy/ssm when your Lambda function uses the Parameters and Secrets Lambda Layer. For SDK-direct access (IAM role assumption, X-Ray capture, parameter paths with wildcards) use @middy/ssm instead.

Prerequisites

Add the AWS Parameters and Secrets Lambda Extension layer to your Lambda function. The AWS_SESSION_TOKEN environment variable is injected automatically by the Lambda runtime.

Incompatible with AWS Lambda Code Signing. The extension is deployed as an AWS-published Lambda Layer. If your function has a Code Signing Configuration that restricts layers to your own approved signing profiles, this layer cannot be attached. In that case use @middy/ssm instead.

Install

To install this middleware you can use NPM:

npm install --save @middy/ssm-extension

Options

  • fetchData (object) (optional): Mapping of internal key name to SSM parameter path.
  • disablePrefetch (boolean) (default false): Disable prefetching on cold start.
  • cacheKey (string) (default @middy/ssm-extension): Cache key for the fetched data. Must be unique across middleware.
  • cacheKeyExpiry (object) (default {}): Per-fetchData-key cache expiry overrides (ms; -1 = forever, 0 = no cache).
  • cacheExpiry (number) (default -1): How long fetch data responses should be cached. -1: cache forever, 0: never cache, n: cache for n ms. Set this to match PARAMETERS_SECRETS_EXTENSION_CACHE_EXPIRATION to avoid stale reads.
  • setToContext (boolean) (default false): Copy fetched values onto request.context.

Notes

  • Lambda is required to have IAM permission for ssm:GetParameter (and kms:Decrypt for SecureString parameters).
  • The extension listens on port 2773 by default. Override with the PARAMETERS_SECRETS_EXTENSION_HTTP_PORT environment variable.
  • String values containing JSON are automatically parsed into objects.

Sample usage

import middy from '@middy/core'
import { getInternal } from '@middy/util'
import ssmExtension from '@middy/ssm-extension'

const lambdaHandler = (event, context) => {
  return {}
}

export const handler = middy()
  .use(
    ssmExtension({
      fetchData: {
        accessToken: '/dev/service_name/access_token'
      },
      cacheExpiry: 15 * 60 * 1000,
      cacheKey: 'ssm-defaults'
    })
  )
  .before(async (request) => {
    const { accessToken } = await getInternal(['accessToken'], request)
    // use accessToken
  })
  .handler(lambdaHandler)

Usage with TypeScript

Use ssmExtensionParam<T>() to provide type hints for fetched values:

import middy from '@middy/core'
import { getInternal } from '@middy/util'
import ssmExtension, { ssmExtensionParam } from '@middy/ssm-extension'
import type { Context as LambdaContext } from 'aws-lambda'

interface DbConfig {
  host: string
  port: number
}

const lambdaHandler = (event: {}, context: LambdaContext) => {
  return {}
}

export const handler = middy()
  .use(
    ssmExtension({
      fetchData: {
        accessToken: ssmExtensionParam<string>('/dev/service/access_token'),
        dbConfig: ssmExtensionParam<DbConfig>('/dev/service/db_config')
      },
      cacheExpiry: 15 * 60 * 1000,
      cacheKey: 'ssm-params'
    })
  )
  .before(async (request) => {
    const data = await getInternal(['accessToken', 'dbConfig'], request)
    // data.accessToken is typed as string
    // data.dbConfig is typed as DbConfig
  })
  .handler(lambdaHandler)