Skip to content

Commit 8fd5479

Browse files
authored
feat(parameters): adds setParameter function to store SSM parameters (#3020)
1 parent 6864e53 commit 8fd5479

12 files changed

+511
-3
lines changed

Diff for: docs/utilities/parameters.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ This utility requires additional permissions to work as expected.
6161
| SSM | **`getParameters`**, **`SSMProvider.getMultiple`** | **`ssm:GetParametersByPath`** |
6262
| SSM | **`getParametersByName`**, **`SSMProvider.getParametersByName`** | **`ssm:GetParameter`** and **`ssm:GetParameters`** |
6363
| SSM | If using **`decrypt: true`** | You must add an additional permission **`kms:Decrypt`** |
64+
| SSM | **`setParameter`**, **`SSMProvider.set`** | **`ssm:PutParameter`** |
6465
| Secrets | **`getSecret`**, **`SecretsProvider.get`** | **`secretsmanager:GetSecretValue`** |
6566
| DynamoDB | **`DynamoDBProvider.get`** | **`dynamodb:GetItem`** |
6667
| DynamoDB | **`DynamoDBProvider.getMultiple`** | **`dynamodb:Query`** |
@@ -104,6 +105,20 @@ For multiple parameters, you can use either:
104105
--8<-- "examples/snippets/parameters/getParametersByNameGracefulErrorHandling.ts"
105106
```
106107

108+
### Storing parameters
109+
110+
You can store parameters in the System Manager Parameter Store using `setParameter`.
111+
112+
```typescript hl_lines="1 5" title="Storing a parameter in SSM"
113+
--8<-- "examples/snippets/parameters/setParameter.ts"
114+
```
115+
116+
If the parameter is already existent, it needs to have the `overwrite` parameter set to `true` to update the value.
117+
118+
```typescript hl_lines="1 7" title="Overwriting an existing parameter in SSM"
119+
--8<-- "examples/snippets/parameters/setParameterOverwrite.ts"
120+
```
121+
107122
### Fetching secrets
108123

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

372387
| Provider | Function/Method | Client name | Function name |
373-
| ------------------- | ------------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
388+
| ------------------- |--------------------------------| --------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
374389
| SSM Parameter Store | `getParameter` | `@aws-sdk/client-ssm` | [GetParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParameterCommand/){target="_blank"} |
375390
| SSM Parameter Store | `getParameters` | `@aws-sdk/client-ssm` | [GetParametersByPathCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParametersByPathCommand/){target="_blank"} |
376391
| SSM Parameter Store | `SSMProvider.get` | `@aws-sdk/client-ssm` | [GetParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParameterCommand/){target="_blank"} |
377392
| SSM Parameter Store | `SSMProvider.getMultiple` | `@aws-sdk/client-ssm` | [GetParametersByPathCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/GetParametersByPathCommand){target="_blank"} |
393+
| SSM Parameter Store | `setParameter` | `@aws-sdk/client-ssm` | [PutParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/PutParameterCommand/){target="_blank"} |
394+
| SSM Parameter Store | `SSMProvider.set` | `@aws-sdk/client-ssm` | [PutParameterCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/command/PutParameterCommand/){target="_blank"} |
378395
| Secrets Manager | `getSecret` | `@aws-sdk/client-secrets-manager` | [GetSecretValueCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/secrets-manager/command/GetSecretValueCommand/){target="_blank"} |
379396
| 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"} |
380397
| 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"} |

Diff for: examples/snippets/parameters/setParameter.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
2+
3+
export const handler = async (): Promise<void> => {
4+
// Store a string parameter
5+
const parameter = await setParameter('/my/parameter', { value: 'my-value' });
6+
console.log(parameter);
7+
};
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
2+
3+
export const handler = async (): Promise<void> => {
4+
// Overwrite a string parameter
5+
const parameter = await setParameter('/my/parameter', {
6+
value: 'my-value',
7+
overwrite: true,
8+
});
9+
console.log(parameter);
10+
};

Diff for: packages/parameters/src/errors.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ class GetParameterError extends Error {
88
}
99
}
1010

11+
/**
12+
* Error thrown when a parameter cannot be set.
13+
*/
14+
class SetParameterError extends Error {
15+
public constructor(message?: string) {
16+
super(message);
17+
this.name = 'SetParameterError';
18+
}
19+
}
20+
1121
/**
1222
* Error thrown when a transform fails.
1323
*/
@@ -19,4 +29,4 @@ class TransformParameterError extends Error {
1929
}
2030
}
2131

22-
export { GetParameterError, TransformParameterError };
32+
export { GetParameterError, TransformParameterError, SetParameterError };

Diff for: packages/parameters/src/ssm/SSMProvider.ts

+62-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { JSONValue } from '@aws-lambda-powertools/commons/types';
22
import {
33
GetParameterCommand,
44
GetParametersCommand,
5+
PutParameterCommand,
56
SSMClient,
67
paginateGetParametersByPath,
78
} from '@aws-sdk/client-ssm';
@@ -10,12 +11,14 @@ import type {
1011
GetParametersByPathCommandInput,
1112
GetParametersCommandInput,
1213
GetParametersCommandOutput,
14+
PutParameterCommandInput,
15+
PutParameterCommandOutput,
1316
SSMPaginationConfiguration,
1417
} from '@aws-sdk/client-ssm';
1518
import { BaseProvider } from '../base/BaseProvider.js';
1619
import { transformValue } from '../base/transformValue.js';
1720
import { DEFAULT_MAX_AGE_SECS } from '../constants.js';
18-
import { GetParameterError } from '../errors.js';
21+
import { GetParameterError, SetParameterError } from '../errors.js';
1922
import type {
2023
SSMGetMultipleOptions,
2124
SSMGetMultipleOutput,
@@ -26,6 +29,7 @@ import type {
2629
SSMGetParametersByNameOutput,
2730
SSMGetParametersByNameOutputInterface,
2831
SSMProviderOptions,
32+
SSMSetOptions,
2933
SSMSplitBatchAndDecryptParametersOutputType,
3034
} from '../types/SSMProvider.js';
3135

@@ -322,6 +326,63 @@ class SSMProvider extends BaseProvider {
322326
>;
323327
}
324328

329+
/**
330+
* Sets a parameter in AWS Systems Manager (SSM).
331+
*
332+
* @example
333+
* ```typescript
334+
* import { SSMProvider } from '@aws-lambda-powertools/parameters/ssm';
335+
*
336+
* const parametersProvider = new SSMProvider();
337+
*
338+
* export const handler = async (): Promise<void> => {
339+
* // Set a parameter in SSM
340+
* const version = await parametersProvider.set('/my-parameter', { value: 'my-value' });
341+
* console.log(`Parameter version: ${version}`);
342+
* };
343+
* ```
344+
*
345+
* You can customize the storage of the value by passing options to the function:
346+
* * `value` - The value of the parameter, which is a mandatory option.
347+
* * `overwrite` - Whether to overwrite the value if it already exists (default: `false`)
348+
* * `description` - The description of the parameter
349+
* * `parameterType` - The type of the parameter, can be one of `String`, `StringList`, or `SecureString` (default: `String`)
350+
* * `tier` - The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering` (default: `Standard`)
351+
* * `kmsKeyId` - The KMS key id to use to encrypt the parameter
352+
* * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client
353+
*
354+
* @param {string} name - The name of the parameter
355+
* @param {SSMSetOptions} options - Options to configure the parameter
356+
* @returns {Promise<number>} The version of the parameter
357+
* @see https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/
358+
*/
359+
public async set<
360+
InferredFromOptionsType extends SSMSetOptions | undefined = SSMSetOptions,
361+
>(
362+
name: string,
363+
options: InferredFromOptionsType & SSMSetOptions
364+
): Promise<number> {
365+
const sdkOptions: PutParameterCommandInput = {
366+
Tier: options.tier ?? 'Standard',
367+
Type: options.parameterType ?? 'String',
368+
Overwrite: options.overwrite ?? false,
369+
...(options.kmsKeyId ? { KeyId: options.kmsKeyId } : {}),
370+
...(options.description ? { Description: options.description } : {}),
371+
...(options?.sdkOptions ?? {}),
372+
Name: name,
373+
Value: options.value,
374+
};
375+
let result: PutParameterCommandOutput;
376+
try {
377+
result = await this.client.send(new PutParameterCommand(sdkOptions));
378+
} catch (error) {
379+
throw new SetParameterError(`Unable to set parameter with name ${name}`);
380+
}
381+
382+
// biome-ignore lint/style/noNonNullAssertion: The API for PutParameter states that there will always be a value returned when the request was successful.
383+
return result.Version!;
384+
}
385+
325386
/**
326387
* Retrieve multiple values from AWS Systems Manager.
327388
*

Diff for: packages/parameters/src/ssm/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { SSMProvider } from './SSMProvider.js';
22
export { getParameter } from './getParameter.js';
3+
export { setParameter } from './setParameter.js';
34
export { getParameters } from './getParameters.js';
45
export { getParametersByName } from './getParametersByName.js';

Diff for: packages/parameters/src/ssm/setParameter.ts

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { DEFAULT_PROVIDERS } from '../base/DefaultProviders.js';
2+
import type { SSMSetOptions } from '../types/SSMProvider.js';
3+
import { SSMProvider } from './SSMProvider.js';
4+
5+
/**
6+
* ## Intro
7+
* The Parameters utility provides an SSMProvider that allows setting parameters in AWS Systems Manager.
8+
*
9+
* ## Getting started
10+
*
11+
* This utility supports AWS SDK v3 for JavaScript only. This allows the utility to be modular, and you to install only
12+
* the SDK packages you need and keep your bundle size small.
13+
*
14+
* To use the provider, you must install the Parameters utility and the AWS SDK v3 for JavaScript for SSM:
15+
*
16+
* ```sh
17+
* npm install @aws-lambda-powertools/parameters @aws-sdk/client-ssm
18+
*```
19+
*
20+
* ## Basic Usage
21+
*
22+
* @example
23+
* ```typescript
24+
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
25+
*
26+
* export const handler = async (): Promise<void> => {
27+
* // Set a parameter
28+
* const version = await setParameter('/my-parameter', { value: 'my-value' });
29+
* console.log(Parameter version: ${version});
30+
* };
31+
* ```
32+
*
33+
* ## Advanced Usage
34+
*
35+
* ### Overwriting a parameter
36+
*
37+
* 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.
38+
*
39+
* @example
40+
* ```typescript
41+
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
42+
*
43+
* export const handler = async (): Promise<void> => {
44+
* // Set a parameter and overwrite it
45+
* const version = await setParameter('/my-parameter', {
46+
* value: 'my-value',
47+
* overwrite: true,
48+
* });
49+
* console.log(Parameter version: ${version});
50+
* };
51+
* ```
52+
*
53+
* ### Extra SDK options
54+
*
55+
* When setting a parameter, you can pass extra options to the AWS SDK v3 for JavaScript client by using the sdkOptions parameter.
56+
*
57+
* @example
58+
* ```typescript
59+
* import { setParameter } from '@aws-lambda-powertools/parameters/ssm';
60+
*
61+
* export const handler = async (): Promise<void> => {
62+
* // Set a parameter with extra options
63+
* const version = await setParameter('/my-parameter', {
64+
* value: 'my-value',
65+
* sdkOptions: {
66+
* Overwrite: true,
67+
* },
68+
* });
69+
* };
70+
* ```
71+
*
72+
* This object accepts the same options as the AWS SDK v3 for JavaScript `PutParameterCommandInput` interface.
73+
*
74+
* ### Built-in provider class
75+
*
76+
* For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use the {@link SSMProvider} class.
77+
*
78+
* ### Options
79+
*
80+
* You can customize the storage of the value by passing options to the function:
81+
* * `value` - The value of the parameter, which is a mandatory option.
82+
* * `overwrite` - Whether to overwrite the value if it already exists (default: `false`)
83+
* * `description` - The description of the parameter
84+
* * `parameterType` - The type of the parameter, can be one of `String`, `StringList`, or `SecureString` (default: `String`)
85+
* * `tier` - The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering` (default: `Standard`)
86+
* * `kmsKeyId` - The KMS key id to use to encrypt the parameter
87+
* * `sdkOptions` - Extra options to pass to the AWS SDK v3 for JavaScript client
88+
*
89+
* For more usage examples, see [our documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/).
90+
*
91+
* @param {string} name - Name of the parameter
92+
* @param {SSMSetOptions} options - Options to configure the parameter
93+
* @see https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parameters/
94+
*/
95+
const setParameter = async <
96+
InferredFromOptionsType extends SSMSetOptions | undefined = SSMSetOptions,
97+
>(
98+
name: string,
99+
options: InferredFromOptionsType & SSMSetOptions
100+
): Promise<number> => {
101+
if (!Object.hasOwn(DEFAULT_PROVIDERS, 'ssm')) {
102+
DEFAULT_PROVIDERS.ssm = new SSMProvider();
103+
}
104+
return (DEFAULT_PROVIDERS.ssm as SSMProvider).set(name, options);
105+
};
106+
107+
export { setParameter };

Diff for: packages/parameters/src/types/SSMProvider.ts

+40
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { JSONValue } from '@aws-lambda-powertools/commons/types';
22
import type {
33
GetParameterCommandInput,
44
GetParametersByPathCommandInput,
5+
PutParameterCommandInput,
56
SSMClient,
67
SSMClientConfig,
78
} from '@aws-sdk/client-ssm';
@@ -94,6 +95,44 @@ type SSMGetOptions =
9495
| SSMGetOptionsTransformNone
9596
| undefined;
9697

98+
type ParameterType = 'String' | 'StringList' | 'SecureString';
99+
100+
type ParameterTier = 'Standard' | 'Advanced' | 'Intelligent-Tiering';
101+
102+
type SSMSetOptions = {
103+
/**
104+
* The parameter value
105+
*/
106+
value: string;
107+
/**
108+
* If the parameter value should be overwritten
109+
* @default false
110+
*/
111+
overwrite?: boolean;
112+
/**
113+
* The description of the parameter
114+
*/
115+
description?: string;
116+
/**
117+
* Type of the parameter, can be one of `String`, `StringList`, or `SecureString`
118+
* @default `String`
119+
*/
120+
parameterType?: ParameterType;
121+
/**
122+
* The parameter tier to use, can be one of `Standard`, `Advanced`, and `Intelligent-Tiering`
123+
* @default `Standard`
124+
*/
125+
tier?: ParameterTier;
126+
/**
127+
* The KMS key id to use to encrypt the parameter
128+
*/
129+
kmsKeyId?: string;
130+
/**
131+
* Additional options to pass to the AWS SDK v3 client
132+
*/
133+
sdkOptions?: Partial<PutParameterCommandInput>;
134+
};
135+
97136
/**
98137
* Generic output type for the SSMProvider get method.
99138
*/
@@ -239,6 +278,7 @@ type SSMGetParametersByNameOutput<InferredFromOptionsType = undefined> =
239278
export type {
240279
SSMProviderOptions,
241280
SSMGetOptions,
281+
SSMSetOptions,
242282
SSMGetOutput,
243283
SSMGetMultipleOptions,
244284
SSMGetMultipleOutput,

0 commit comments

Comments
 (0)