Skip to content

feat(parameters): adds setParameter function to store SSM parameters #3020

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

Merged
19 changes: 18 additions & 1 deletion docs/utilities/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ This utility requires additional permissions to work as expected.
| SSM | **`getParameters`**, **`SSMProvider.getMultiple`** | **`ssm:GetParametersByPath`** |
| SSM | **`getParametersByName`**, **`SSMProvider.getParametersByName`** | **`ssm:GetParameter`** and **`ssm:GetParameters`** |
| SSM | If using **`decrypt: true`** | You must add an additional permission **`kms:Decrypt`** |
| SSM | **`setParameter`**, **`SSMProvider.set`** | **`ssm:PutParameter`** |
| Secrets | **`getSecret`**, **`SecretsProvider.get`** | **`secretsmanager:GetSecretValue`** |
| DynamoDB | **`DynamoDBProvider.get`** | **`dynamodb:GetItem`** |
| DynamoDB | **`DynamoDBProvider.getMultiple`** | **`dynamodb:Query`** |
Expand Down Expand Up @@ -104,6 +105,20 @@ For multiple parameters, you can use either:
--8<-- "examples/snippets/parameters/getParametersByNameGracefulErrorHandling.ts"
```

### Storing parameters

You can store parameters in the System Manager Parameter Store using `setParameter`.

```typescript hl_lines="1 5" title="Storing a parameter in SSM"
--8<-- "examples/snippets/parameters/setParameter.ts"
```

If the parameter is already existent, it needs to have the `overwrite` parameter set to `true` to update the value.

```typescript hl_lines="1 7" title="Overwriting an existing parameter in SSM"
--8<-- "examples/snippets/parameters/setParameterOverwrite.ts"
```

### Fetching secrets

You can fetch secrets stored in Secrets Manager using `getSecret`.
Expand Down Expand Up @@ -370,11 +385,13 @@ You can use a special `sdkOptions` object argument to pass any supported option
Here is the mapping between this utility's functions and methods and the underlying SDK:

| Provider | Function/Method | Client name | Function name |
| ------------------- | ------------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ------------------- |--------------------------------| --------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| SSM Parameter Store | `getParameter` | `@aws-sdk/client-ssm` | [GetParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParameterCommand/){target="_blank"} |
| SSM Parameter Store | `getParameters` | `@aws-sdk/client-ssm` | [GetParametersByPathCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParametersByPathCommand/){target="_blank"} |
| SSM Parameter Store | `SSMProvider.get` | `@aws-sdk/client-ssm` | [GetParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParameterCommand/){target="_blank"} |
| SSM Parameter Store | `SSMProvider.getMultiple` | `@aws-sdk/client-ssm` | [GetParametersByPathCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParametersByPathCommand){target="_blank"} |
| SSM Parameter Store | `setParameter` | `@aws-sdk/client-ssm` | [PutParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/PutParameterCommand/){target="_blank"} |
| SSM Parameter Store | `SSMProvider.set` | `@aws-sdk/client-ssm` | [PutParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/PutParameterCommand/){target="_blank"} |
| Secrets Manager | `getSecret` | `@aws-sdk/client-secrets-manager` | [GetSecretValueCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/secrets-manager/command/GetSecretValueCommand/){target="_blank"} |
| Secrets Manager | `SecretsProvider.get` | `@aws-sdk/client-secrets-manager` | [GetSecretValueCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/secrets-manager/command/GetSecretValueCommand/){target="_blank"} |
| AppConfig | `AppConfigProvider.get` | `@aws-sdk/client-appconfigdata` | [StartConfigurationSessionCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/appconfigdata/command/StartConfigurationSessionCommand/){target="_blank"} & [GetLatestConfigurationCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/appconfigdata/command/GetLatestConfigurationCommand/){target="_blank"} |
Expand Down
7 changes: 7 additions & 0 deletions examples/snippets/parameters/setParameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { setParameter } from '@aws-lambda-powertools/parameters/ssm';

export const handler = async (): Promise<void> => {
// Store a string parameter
const parameter = await setParameter('/my/parameter', { value: 'my-value' });
console.log(parameter);
};
10 changes: 10 additions & 0 deletions examples/snippets/parameters/setParameterOverwrite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { setParameter } from '@aws-lambda-powertools/parameters/ssm';

export const handler = async (): Promise<void> => {
// Overwrite a string parameter
const parameter = await setParameter('/my/parameter', {
value: 'my-value',
overwrite: true,
});
console.log(parameter);
};
12 changes: 11 additions & 1 deletion packages/parameters/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ class GetParameterError extends Error {
}
}

/**
* Error thrown when a parameter cannot be set.
*/
class SetParameterError extends Error {
public constructor(message?: string) {
super(message);
this.name = 'SetParameterError';
}
}

/**
* Error thrown when a transform fails.
*/
Expand All @@ -19,4 +29,4 @@ class TransformParameterError extends Error {
}
}

export { GetParameterError, TransformParameterError };
export { GetParameterError, TransformParameterError, SetParameterError };
63 changes: 62 additions & 1 deletion packages/parameters/src/ssm/SSMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { JSONValue } from '@aws-lambda-powertools/commons/types';
import {
GetParameterCommand,
GetParametersCommand,
PutParameterCommand,
SSMClient,
paginateGetParametersByPath,
} from '@aws-sdk/client-ssm';
Expand All @@ -10,12 +11,14 @@ import type {
GetParametersByPathCommandInput,
GetParametersCommandInput,
GetParametersCommandOutput,
PutParameterCommandInput,
PutParameterCommandOutput,
SSMPaginationConfiguration,
} from '@aws-sdk/client-ssm';
import { BaseProvider } from '../base/BaseProvider.js';
import { transformValue } from '../base/transformValue.js';
import { DEFAULT_MAX_AGE_SECS } from '../constants.js';
import { GetParameterError } from '../errors.js';
import { GetParameterError, SetParameterError } from '../errors.js';
import type {
SSMGetMultipleOptions,
SSMGetMultipleOutput,
Expand All @@ -26,6 +29,7 @@ import type {
SSMGetParametersByNameOutput,
SSMGetParametersByNameOutputInterface,
SSMProviderOptions,
SSMSetOptions,
SSMSplitBatchAndDecryptParametersOutputType,
} from '../types/SSMProvider.js';

Expand Down Expand Up @@ -322,6 +326,63 @@ class SSMProvider extends BaseProvider {
>;
}

/**
* Sets a parameter in AWS Systems Manager (SSM).
*
* @example
* ```typescript
* import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm';
*
* const parametersProvider = new SSMProvider();
*
* export const handler = async (): Promise<void> => {
* // Set a parameter in SSM
* const version = await parametersProvider.set('/my-parameter', { value: 'my-value' });
* console.log(`Parameter version: ${version}`);
* };
* ```
*
* You can customize the storage of the value by passing options to the function:
* * `value` - The value of the parameter, which is a mandatory option.
* * `overwrite` - Whether to overwrite the value if it already exists (default: `false`)
* * `description` - The description of the parameter
* * `parameterType` - The type of the parameter, can be one of `String`, `StringList`, or `SecureString` (default: `String`)
* * `tier` - The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering` (default: `Standard`)
* * `kmsKeyId` - The KMS key id to use to encrypt the parameter
* * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client
*
* @param {string} name - The name of the parameter
* @param {SSMSetOptions} options - Options to configure the parameter
* @returns {Promise<number>} The version of the parameter
* @see https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/
*/
public async set<
InferredFromOptionsType extends SSMSetOptions | undefined = SSMSetOptions,
>(
name: string,
options: InferredFromOptionsType & SSMSetOptions
): Promise<number> {
const sdkOptions: PutParameterCommandInput = {
Tier: options.tier ?? 'Standard',
Type: options.parameterType ?? 'String',
Overwrite: options.overwrite ?? false,
...(options.kmsKeyId ? { KeyId: options.kmsKeyId } : {}),
...(options.description ? { Description: options.description } : {}),
...(options?.sdkOptions ?? {}),
Name: name,
Value: options.value,
};
let result: PutParameterCommandOutput;
try {
result = await this.client.send(new PutParameterCommand(sdkOptions));
} catch (error) {
throw new SetParameterError(`Unable to set parameter with name ${name}`);
}

// biome-ignore lint/style/noNonNullAssertion: The API for PutParameter states that there will always be a value returned when the request was successful.
return result.Version!;
}

/**
* Retrieve multiple values from AWS Systems Manager.
*
Expand Down
1 change: 1 addition & 0 deletions packages/parameters/src/ssm/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { SSMProvider } from './SSMProvider.js';
export { getParameter } from './getParameter.js';
export { setParameter } from './setParameter.js';
export { getParameters } from './getParameters.js';
export { getParametersByName } from './getParametersByName.js';
107 changes: 107 additions & 0 deletions packages/parameters/src/ssm/setParameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { DEFAULT_PROVIDERS } from '../base/DefaultProviders.js';
import type { SSMSetOptions } from '../types/SSMProvider.js';
import { SSMProvider } from './SSMProvider.js';

/**
* ## Intro
* The Parameters utility provides an SSMProvider that allows setting parameters in AWS Systems Manager.
*
* ## Getting started
*
* This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only
* the SDK packages you need and keep your bundle size small.
*
* To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for SSM:
*
* ```sh
* npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm
*```
*
* ## Basic Usage
*
* @example
* ```typescript
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
*
* export const handler = async (): Promise<void> => {
* // Set a parameter
* const version = await setParameter('/my-parameter', { value: 'my-value' });
* console.log(Parameter version: ${version});
* };
* ```
*
* ## Advanced Usage
*
* ### Overwriting a parameter
*
* By default, the provider will not overwrite a parameter if it already exists. You can force the provider to overwrite the parameter by using the `overwrite` option.
*
* @example
* ```typescript
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
*
* export const handler = async (): Promise<void> => {
* // Set a parameter and overwrite it
* const version = await setParameter('/my-parameter', {
* value: 'my-value',
* overwrite: true,
* });
* console.log(Parameter version: ${version});
* };
* ```
*
* ### Extra SDK options
*
* When setting a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the sdkOptions parameter.
*
* @example
* ```typescript
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
*
* export const handler = async (): Promise<void> => {
* // Set a parameter with extra options
* const version = await setParameter('/my-parameter', {
* value: 'my-value',
* sdkOptions: {
* Overwrite: true,
* },
* });
* };
* ```
*
* This object accepts the same options as the AWS SDK v3 for JavaScript `PutParameterCommandInput` interface.
*
* ### Built-in provider class
*
* For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class.
*
* ### Options
*
* You can customize the storage of the value by passing options to the function:
* * `value` - The value of the parameter, which is a mandatory option.
* * `overwrite` - Whether to overwrite the value if it already exists (default: `false`)
* * `description` - The description of the parameter
* * `parameterType` - The type of the parameter, can be one of `String`, `StringList`, or `SecureString` (default: `String`)
* * `tier` - The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering` (default: `Standard`)
* * `kmsKeyId` - The KMS key id to use to encrypt the parameter
* * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client
*
* For more usage examples, see [our documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/).
*
* @param {string} name - Name of the parameter
* @param {SSMSetOptions} options - Options to configure the parameter
* @see https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/
*/
const setParameter = async <
InferredFromOptionsType extends SSMSetOptions | undefined = SSMSetOptions,
>(
name: string,
options: InferredFromOptionsType & SSMSetOptions
): Promise<number> => {
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'ssm')) {
DEFAULT_PROVIDERS.ssm = new SSMProvider();
}
return (DEFAULT_PROVIDERS.ssm as SSMProvider).set(name, options);
};

export { setParameter };
40 changes: 40 additions & 0 deletions packages/parameters/src/types/SSMProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { JSONValue } from '@aws-lambda-powertools/commons/types';
import type {
GetParameterCommandInput,
GetParametersByPathCommandInput,
PutParameterCommandInput,
SSMClient,
SSMClientConfig,
} from '@aws-sdk/client-ssm';
Expand Down Expand Up @@ -94,6 +95,44 @@ type SSMGetOptions =
| SSMGetOptionsTransformNone
| undefined;

type ParameterType = 'String' | 'StringList' | 'SecureString';

type ParameterTier = 'Standard' | 'Advanced' | 'Intelligent-Tiering';

type SSMSetOptions = {
/**
* The parameter value
*/
value: string;
/**
* If the parameter value should be overwritten
* @default false
*/
overwrite?: boolean;
/**
* The description of the parameter
*/
description?: string;
/**
* Type of the parameter, can be one of `String`, `StringList`, or `SecureString`
* @default `String`
*/
parameterType?: ParameterType;
/**
* The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering`
* @default `Standard`
*/
tier?: ParameterTier;
/**
* The KMS key id to use to encrypt the parameter
*/
kmsKeyId?: string;
/**
* Additional options to pass to the AWS SDK v3 client
*/
sdkOptions?: Partial<PutParameterCommandInput>;
};

/**
* Generic output type for the SSMProvider get method.
*/
Expand Down Expand Up @@ -239,6 +278,7 @@ type SSMGetParametersByNameOutput<InferredFromOptionsType = undefined> =
export type {
SSMProviderOptions,
SSMGetOptions,
SSMSetOptions,
SSMGetOutput,
SSMGetMultipleOptions,
SSMGetMultipleOutput,
Expand Down
Loading