From ba6c0c2c719d6b3c4ff24a45b8eebd80abf8eab0 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 Jun 2023 17:46:52 +0200 Subject: [PATCH 1/5] chore: remove beta notice from README + headings --- packages/parameters/README.md | 45 +++++++++++++++-------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/packages/parameters/README.md b/packages/parameters/README.md index f2178eead6..b4c041c26e 100644 --- a/packages/parameters/README.md +++ b/packages/parameters/README.md @@ -1,21 +1,16 @@ # Powertools for AWS Lambda (TypeScript) -| ⚠️ **WARNING: Do not use this utility in production just yet!** ⚠️ | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **This utility is currently released as beta developer preview** and is intended strictly for feedback and testing purposes **and not for production workloads**.. The version and all future versions tagged with the `-beta` suffix should be treated as not stable. Up until before the [General Availability release](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/10) we might introduce significant breaking changes and improvements in response to customers feedback. | _ | - -Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://docs.powertools.aws.dev/lambda-typescript/latest/#features). +Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://docs.powertools.aws.dev/lambda/typescript/latest/#features). You can use the package in both TypeScript and JavaScript code bases. - [Intro](#intro) - [Key features](#key-features) - [Usage](#usage) - - [SSMProvider](#ssmprovider) - - [Fetching parameters](#fetching-parameters) - - [SecretsProvider](#secretsprovider) - - [DynamoDBProvider](#dynamodbprovider) - - [AppConfigProvider](#appconfigprovider) + - [Fetching parameters from AWS SSM Parameter Store](#fetching-parameters-from-aws-ssm-parameter-store) + - [Getting secrets from Amazon Secrets Manager](#getting-secrets-from-amazon-secrets-manager) + - [Retrieving values from Amazon DynamoDB](#retrieving-values-from-amazon-dynamodb) + - [Fetching configs from AWS AppConfig](#fetching-configs-from-aws-appconfig) - [Contribute](#contribute) - [Roadmap](#roadmap) - [Connect](#connect) @@ -39,7 +34,7 @@ The Parameters utility provides high-level functions to retrieve one or multiple ## Usage -### SSMProvider +### Fetching parameters from AWS SSM Parameter Store To get started, install the library and the corresponding AWS SDK for JavaScript v3: @@ -47,9 +42,7 @@ To get started, install the library and the corresponding AWS SDK for JavaScript npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm ``` -Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda-typescript/1.9.0/utilities/parameters/#iam-permissions) in the documentation of the utility. - -#### Fetching parameters +Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#iam-permissions) in the documentation of the utility. You can retrieve a single parameter using the `getParameter` high-level function. @@ -105,9 +98,9 @@ export const handler = async (): Promise => { }; ``` -Check the [docs](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#fetching-parameters) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. +Check the [docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#fetching-parameters) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. -### SecretsProvider +### Getting secrets from Amazon Secrets Manager To get started, install the library and the corresponding AWS SDK for JavaScript v3: @@ -115,7 +108,7 @@ To get started, install the library and the corresponding AWS SDK for JavaScript npm install @aws-lambda-powertools/parameters @aws-sdk/client-secrets-manager ``` -Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda-typescript/1.9.0/utilities/parameters/#iam-permissions) in the documentation of the utility. +Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#iam-permissions) in the documentation of the utility. You can fetch secrets stored in Secrets Manager using the `getSecret` function: @@ -129,9 +122,9 @@ export const handler = async (): Promise => { }; ``` -Check the [docs](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#fetching-secrets) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. +Check the [docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#fetching-secrets) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. -### DynamoDBProvider +### Retrieving values from Amazon DynamoDB To get started, install the library and the corresponding AWS SDK for JavaScript v3: @@ -139,7 +132,7 @@ To get started, install the library and the corresponding AWS SDK for JavaScript npm install @aws-lambda-powertools/parameters @aws-sdk/client-dynamodb @aws-sdk/util-dynamodb ``` -Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda-typescript/1.9.0/utilities/parameters/#iam-permissions) in the documentation of the utility. +Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#iam-permissions) in the documentation of the utility. You can retrieve a single parameter from DynamoDB using the `DynamoDBProvider.get()` method: @@ -176,10 +169,10 @@ export const handler = async (): Promise => { }; ``` -Check the [docs](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#fetching-secrets) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. +Check the [docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#fetching-secrets) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. -### AppConfigProvider +### Fetching configs from AWS AppConfig To get started, install the library and the corresponding AWS SDK for JavaScript v3: @@ -187,7 +180,7 @@ To get started, install the library and the corresponding AWS SDK for JavaScript npm install @aws-lambda-powertools/parameters @aws-sdk/client-appconfigdata ``` -Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda-typescript/1.9.0/utilities/parameters/#iam-permissions) in the documentation of the utility. +Next, review the IAM permissions attached to your AWS Lambda function and make sure you allow the [actions detailed](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#iam-permissions) in the documentation of the utility. You can fetch application configurations in AWS AppConfig using the `getAppConfig` function: @@ -204,7 +197,7 @@ export const handler = async (): Promise => { }; ``` -Check the [docs](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#fetching-app-configurations) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. +Check the [docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#fetching-app-configurations) for more examples, and [the advanced section](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/#advanced) for details about caching, transforms, customizing the underlying SDK, and more. ## Contribute @@ -212,7 +205,7 @@ If you are interested in contributing to this project, please refer to our [Cont ## Roadmap -[The roadmap](https://docs.powertools.aws.dev/lambda-typescript/latest/roadmap/) of Powertools for AWS Lambda (TypeScript) is driven by customers’ demand. +[The roadmap](https://docs.powertools.aws.dev/lambda/typescript/latest/roadmap/) of Powertools for AWS Lambda (TypeScript) is driven by customers’ demand. Help us prioritize upcoming functionalities or utilities by [upvoting existing RFCs and feature requests](https://github.com/aws-powertools/powertools-lambda-typescript/issues), or [creating new ones](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose), in this GitHub repository. ## Connect @@ -239,7 +232,7 @@ The following companies, among others, use Powertools: ### Sharing your work -Share what you did with Powertools for AWS Lambda (TypeScript) 💞💞. Blog post, workshops, presentation, sample apps and others. Check out what the community has already shared about Powertools for AWS Lambda (TypeScript) [here](https://docs.powertools.aws.dev/lambda-typescript/latest/we_made_this). +Share what you did with Powertools for AWS Lambda (TypeScript) 💞💞. Blog post, workshops, presentation, sample apps and others. Check out what the community has already shared about Powertools for AWS Lambda (TypeScript) [here](https://docs.powertools.aws.dev/lambda/typescript/latest/we_made_this). ### Using Lambda Layer From 7c9e2a112d682c172f2bcc7ad7a77c6fc8640a3a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 Jun 2023 17:47:10 +0200 Subject: [PATCH 2/5] chore: remove utility from beta pool --- .github/scripts/release_patch_package_json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/release_patch_package_json.js b/.github/scripts/release_patch_package_json.js index 51fd432124..68d23adcc5 100644 --- a/.github/scripts/release_patch_package_json.js +++ b/.github/scripts/release_patch_package_json.js @@ -18,7 +18,7 @@ if (process.argv.length < 3) { const basePath = resolve(process.argv[2]); const packageJsonPath = join(basePath, 'package.json'); const alphaPackages = ['@aws-lambda-powertools/idempotency']; -const betaPackages = ['@aws-lambda-powertools/parameters']; +const betaPackages = []; (() => { try { From 75f26e3a65160132a863e1db6f3cefa2633e9acd Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 Jun 2023 17:48:39 +0200 Subject: [PATCH 3/5] chore: remove beta notice from other readmes --- README.md | 2 +- packages/commons/README.md | 2 +- packages/logger/README.md | 2 +- packages/metrics/README.md | 2 +- packages/tracer/README.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1e5fc60bf3..03746c86a5 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Tracer](https://docs.powertools.aws.dev/lambda-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions * **[Logger](https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM Parameter Store, AWS Secrets Manager, AWS AppConfig, and Amazon DynamoDB +* **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM Parameter Store, AWS Secrets Manager, AWS AppConfig, and Amazon DynamoDB * **[Idempotency (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/idempotency/)** - Class method decorator, Middy middleware, and function wrapper to make your Lambda functions idempotent and prevent duplicate execution based on payload content ## Getting started diff --git a/packages/commons/README.md b/packages/commons/README.md index 357c61ead7..6d62247577 100644 --- a/packages/commons/README.md +++ b/packages/commons/README.md @@ -31,7 +31,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Tracer](https://docs.powertools.aws.dev/lambda-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions * **[Logger](https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB +* **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB ## Getting started diff --git a/packages/logger/README.md b/packages/logger/README.md index 50f77c6e2e..ff8b873201 100644 --- a/packages/logger/README.md +++ b/packages/logger/README.md @@ -30,7 +30,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Tracer](https://docs.powertools.aws.dev/lambda-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions * **[Logger](https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB +* **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB ## Getting started diff --git a/packages/metrics/README.md b/packages/metrics/README.md index bfc62376d2..3df94a668a 100644 --- a/packages/metrics/README.md +++ b/packages/metrics/README.md @@ -30,7 +30,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Tracer](https://docs.powertools.aws.dev/lambda-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions * **[Logger](https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB +* **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB ## Getting started diff --git a/packages/tracer/README.md b/packages/tracer/README.md index bfc62376d2..3df94a668a 100644 --- a/packages/tracer/README.md +++ b/packages/tracer/README.md @@ -30,7 +30,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Tracer](https://docs.powertools.aws.dev/lambda-typescript/latest/core/tracer/)** - Utilities to trace Lambda function handlers, and both synchronous and asynchronous functions * **[Logger](https://docs.powertools.aws.dev/lambda-typescript/latest/core/logger/)** - Structured logging made easier, and a middleware to enrich log items with key details of the Lambda context * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) -* **[Parameters (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB +* **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM, Secrets Manager, AppConfig, and DynamoDB ## Getting started From 5ef74618da8bba3da83dc138a582894db5cd0769 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 Jun 2023 17:58:36 +0200 Subject: [PATCH 4/5] docs: removed beta notice from docs --- docs/utilities/parameters.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index 79a3fb2cfe..c906fd4fd2 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -3,9 +3,6 @@ title: Parameters description: Utility --- -???+ warning - **This utility is currently released as beta developer preview** and is intended strictly for feedback and testing purposes **and not for production workloads**.. The version and all future versions tagged with the `-beta` suffix should be treated as not stable. Up until before the [General Availability release](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/10) we might introduce significant breaking changes and improvements in response to customers feedback. - The Parameters utility provides high-level functions to retrieve one or multiple parameter values from [AWS Systems Manager Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html){target="_blank"}, [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html){target="_blank"}, [AWS AppConfig](https://docs.aws.amazon.com/appconfig/latest/userguide/what-is-appconfig.html){target="_blank"}, [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html){target="_blank"}, or your own parameter store. ## Key features From 19e586cfe72266d99dfcbeb2176817f24f6c6541 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 28 Jun 2023 19:03:23 +0200 Subject: [PATCH 5/5] docs: add custom provider example --- docs/snippets/package.json | 3 +- .../parameters/customProviderVault.ts | 116 ++++++++++++++++++ .../parameters/customProviderVaultTypes.ts | 97 +++++++++++++++ .../parameters/customProviderVaultUsage.ts | 12 ++ docs/utilities/parameters.md | 23 ++++ package-lock.json | 20 ++- 6 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 docs/snippets/parameters/customProviderVault.ts create mode 100644 docs/snippets/parameters/customProviderVaultTypes.ts create mode 100644 docs/snippets/parameters/customProviderVaultUsage.ts diff --git a/docs/snippets/package.json b/docs/snippets/package.json index b79b21cf60..0ce221ad60 100644 --- a/docs/snippets/package.json +++ b/docs/snippets/package.json @@ -35,6 +35,7 @@ "aws-sdk": "^2.1405.0", "aws-sdk-client-mock": "^2.2.0", "aws-sdk-client-mock-jest": "^2.2.0", - "axios": "^1.2.4" + "axios": "^1.2.4", + "hashi-vault-js": "^0.4.13" } } diff --git a/docs/snippets/parameters/customProviderVault.ts b/docs/snippets/parameters/customProviderVault.ts new file mode 100644 index 0000000000..9fea8f22aa --- /dev/null +++ b/docs/snippets/parameters/customProviderVault.ts @@ -0,0 +1,116 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { BaseProvider } from '@aws-lambda-powertools/parameters/base'; +import Vault from 'hashi-vault-js'; +import { isErrorResponse } from './customProviderVaultTypes'; +import type { + HashiCorpVaultProviderOptions, + HashiCorpVaultGetOptions, +} from './customProviderVaultTypes'; + +class HashiCorpVaultProvider extends BaseProvider { + public client: Vault; + readonly #token: string; + readonly #logger: Logger; + + /** + * It initializes the HashiCorpVaultProvider class. + * + * @param {HashiCorpVaultProviderOptions} config - The configuration object. + */ + public constructor(config: HashiCorpVaultProviderOptions) { + super(); + + const { url, token, clientConfig, vaultClient } = config; + if (vaultClient) { + if (vaultClient instanceof Vault) { + this.client = vaultClient; + } else { + throw Error('Not a valid Vault client provided'); + } + } else { + const config: Vault.VaultConfig = { + baseUrl: url, + ...(clientConfig ?? { + timeout: 10000, + rootPath: '', + }), + }; + this.client = new Vault(config); + } + this.#token = token; + this.#logger = new Logger({ + serviceName: 'HashiCorpVaultProvider', + }); + } + + /** + * Retrieve a secret from HashiCorp Vault. + * + * You can customize the retrieval of the secret by passing options to the function: + * * `maxAge` - The maximum age of the value in cache before fetching a new one (in seconds) (default: 5) + * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache + * * `sdkOptions` - Extra options to pass to the HashiCorp Vault SDK, e.g. `mount` or `version` + * + * @param {string} name - The name of the secret + * @param {HashiCorpVaultGetOptions} options - Options to customize the retrieval of the secret + */ + public async get( + name: string, + options?: HashiCorpVaultGetOptions + ): Promise | undefined> { + return super.get(name, options) as Promise< + Record | undefined + >; + } + + /** + * Retrieving multiple parameter values is not supported with HashiCorp Vault. + */ + public async getMultiple(path: string, _options?: unknown): Promise { + await super.getMultiple(path); + } + + /** + * Retrieve a secret from HashiCorp Vault. + * + * @param {string} name - The name of the secret + * @param {HashiCorpVaultGetOptions} options - Options to customize the retrieval of the secret + */ + protected async _get( + name: string, + options?: HashiCorpVaultGetOptions + ): Promise> { + const mount = options?.sdkOptions?.mount ?? 'secret'; + const version = options?.sdkOptions?.version; + + const response = await this.client.readKVSecret( + this.#token, + name, + version, + mount + ); + + if (isErrorResponse(response)) { + this.#logger.error('An error occurred', { + error: response.vaultHelpMessage, + }); + throw response; + } else { + return response.data; + } + } + + /** + * Retrieving multiple parameter values from HashiCorp Vault is not supported. + * + * @throws Not Implemented Error. + */ + protected async _getMultiple( + _path: string, + _options?: unknown + ): Promise { + throw new Error('Method not implemented.'); + } +} + +export { HashiCorpVaultProvider }; diff --git a/docs/snippets/parameters/customProviderVaultTypes.ts b/docs/snippets/parameters/customProviderVaultTypes.ts new file mode 100644 index 0000000000..09845d3cbd --- /dev/null +++ b/docs/snippets/parameters/customProviderVaultTypes.ts @@ -0,0 +1,97 @@ +import { GetOptionsInterface } from '@aws-lambda-powertools/parameters/base/types'; +import type Vault from 'hashi-vault-js'; + +/** + * Base interface for HashiCorpVaultProviderOptions. + * @interface + */ +interface HashiCorpVaultProviderOptionsBase { + /** + * Indicate the server name/IP, port and API version for the Vault instance, all paths are relative to this one. + * @example 'https://vault.example.com:8200/v1' + */ + url: string; + /** + * The Vault token to use for authentication. + */ + token: string; +} + +/** + * Interface for HashiCorpVaultProviderOptions with clientConfig property. + * @interface + */ +interface HashiCorpVaultProviderOptionsWithClientConfig + extends HashiCorpVaultProviderOptionsBase { + /** + * Optional configuration to pass during client initialization to customize the `hashi-vault-js` client. + */ + clientConfig?: Omit; + /** + * This property should never be passed. + */ + vaultClient?: never; +} + +/** + * Interface for HashiCorpVaultProviderOptions with vaultClient property. + * + * @interface + */ +interface HashiCorpVaultProviderOptionsWithClientInstance + extends HashiCorpVaultProviderOptionsBase { + /** + * Optional `hashi-vault-js` client to pass during HashiCorpVaultProvider class instantiation. If not provided, a new client will be created. + */ + vaultClient?: Vault; + /** + * This property should never be passed. + */ + clientConfig: never; +} + +/** + * Options for the HashiCorpVaultProvider class constructor. + * + * @param {string} url - Indicate the server name/IP, port and API version for the Vault instance, all paths are relative to this one. + * @param {string} token - The Vault token to use for authentication. + * @param {Vault.VaultConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. timeout. Mutually exclusive with vaultClient. + * @param {Vault} [vaultClient] - Optional `hashi-vault-js` client to pass during HashiCorpVaultProvider class instantiation. Mutually exclusive with clientConfig. + */ +type HashiCorpVaultProviderOptions = + | HashiCorpVaultProviderOptionsWithClientConfig + | HashiCorpVaultProviderOptionsWithClientInstance; + +type HashiCorpVaultReadKVSecretOptions = { + /** + * The mount point of the secret engine to use. Defaults to `secret`. + * @example 'kv' + */ + mount?: string; + /** + * The version of the secret to retrieve. Defaults to `undefined`. + * @example 1 + */ + version?: number; +}; + +interface HashiCorpVaultGetOptions extends GetOptionsInterface { + /** + * The Parameters utility does not support transforming `Record` values as returned by the HashiCorp Vault SDK. + */ + transform?: never; + sdkOptions?: HashiCorpVaultReadKVSecretOptions; +} + +/** + * Typeguard that discriminates the type of the response and excludes the ErrorResponse type. + * + * @param object The response object to discriminate + */ +export const isErrorResponse = ( + object: Vault.ReadKVSecretResponse +): object is Vault.ErrorResponse => { + return 'isVaultError' in object; +}; + +export type { HashiCorpVaultProviderOptions, HashiCorpVaultGetOptions }; diff --git a/docs/snippets/parameters/customProviderVaultUsage.ts b/docs/snippets/parameters/customProviderVaultUsage.ts new file mode 100644 index 0000000000..203724b69e --- /dev/null +++ b/docs/snippets/parameters/customProviderVaultUsage.ts @@ -0,0 +1,12 @@ +import { HashiCorpVaultProvider } from './customProviderVault'; + +const secretsProvider = new HashiCorpVaultProvider({ + url: 'https://vault.example.com:8200/v1', + token: 'my-token', +}); + +export const handler = async (): Promise => { + // Retrieve a secret from HashiCorp Vault + const secret = await secretsProvider.get('my-secret'); + console.log(secret); +}; diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index c906fd4fd2..75c3363ef9 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -272,6 +272,29 @@ DynamoDB provider can be customized at initialization to match your table struct --8<-- "docs/snippets/parameters/dynamoDBProviderCustomizeTable.ts" ``` +### Create your own provider + +You can create your own custom parameter store provider by extending the `BaseProvider` class, and implementing the `get()` and `getMultiple()` methods, as well as its respective `_get()` and `_getMultiple()` private methods to retrieve a single, or multiple parameters from your custom store. + +All caching logic is handled by the `BaseProvider`, and provided that the return types of your store are compatible with the ones used in the `BaseProvider`, all transformations will also work as expected. + +Here's an example of implementing a custom parameter store using an external service like HashiCorp Vault, a widely popular key-value secret storage. + +=== "Provider implementation" + ```typescript + --8<-- "docs/snippets/parameters/customProviderVault.ts" + ``` + +=== "Provider types" + ```typescript + --8<-- "docs/snippets/parameters/customProviderVaultTypes.ts" + ``` + +=== "Provider usage" + ```typescript + --8<-- "docs/snippets/parameters/customProviderVaultUsage.ts" + ``` + ### Deserializing values with transform parameter For parameters stored in JSON or Base64 format, you can use the `transform` argument for deserialization. diff --git a/package-lock.json b/package-lock.json index acba9128f7..61e1cadf28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,8 @@ "aws-sdk": "^2.1405.0", "aws-sdk-client-mock": "^2.2.0", "aws-sdk-client-mock-jest": "^2.2.0", - "axios": "^1.2.4" + "axios": "^1.2.4", + "hashi-vault-js": "^0.4.13" } }, "docs/snippets/node_modules/@jest/expect-utils": { @@ -6453,9 +6454,10 @@ } }, "node_modules/axios": { - "version": "1.2.4", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "dev": true, - "license": "MIT", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -10216,6 +10218,18 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, + "node_modules/hashi-vault-js": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/hashi-vault-js/-/hashi-vault-js-0.4.13.tgz", + "integrity": "sha512-0M+3/kZ39LQXrQ7QDkPjaYJbUrYZR1MvaJJeodMhYyxs4xG5J56TOpFacDV5TIgUbvUvqiIvriUxtQ8z7BiJvQ==", + "dev": true, + "dependencies": { + "axios": "^1.3.4" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/hosted-git-info": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz",