Skip to content

Commit

Permalink
feat(parameters): adds setParameter function to store SSM parameters (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
daschaa authored Sep 11, 2024
1 parent 6864e53 commit 8fd5479
Show file tree
Hide file tree
Showing 12 changed files with 511 additions and 3 deletions.
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

0 comments on commit 8fd5479

Please sign in to comment.