Skip to content

Commit 043be44

Browse files
authored
feat(aws-ssm): add decryption support for SecureString parameters (#1241)
Signed-off-by: Giovanni De Giorgio <[email protected]>
1 parent ea9e62a commit 043be44

File tree

8 files changed

+75
-11
lines changed

8 files changed

+75
-11
lines changed

assets/aws-ssm/create-param.png

106 KB
Loading

assets/aws-ssm/search.png

14.2 KB
Loading

assets/aws-ssm/ssm-menu.png

54.3 KB
Loading

libs/providers/aws-ssm/README.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,41 @@ OpenFeature.setProvider(
3030
})
3131
);
3232
```
33+
34+
# AWS SSM Provider Configuration
35+
36+
## AwsSsmProviderConfig
37+
38+
| Property | Type | Description | Default |
39+
|-----------------|--------------------|----------------------------------------------|---------|
40+
| `ssmClientConfig` | `SSMClientConfig` | AWS SSM Client configuration options. | See [here](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/ssm/) |
41+
| `enableDecryption` | `boolean` | Enable decryption for SecureString parameters | false |
42+
| `cacheOpts` | `LRUCacheConfig` | Configuration for the local LRU cache. | See below |
43+
44+
## LRUCacheConfig
45+
46+
| Property | Type | Description | Default |
47+
|-----------|--------|------------------------------------------------|---------|
48+
| `enabled` | `boolean` | Whether caching is enabled. | `false` |
49+
| `ttl` | `number` | Time-to-live (TTL) for cached items (in ms). | `300000` (5 minutes) |
50+
| `size` | `number` | Maximum number of items in the cache. | `1000` |
51+
52+
53+
54+
3355
## Retrieve Feature Flag!
3456

35-
Create a new SSM Param called 'my-feature-flag' in your AWS Account and then retrieve it via OpenFeature Client!
57+
Open your AWS Management Console and go to AWS System Manager service
58+
59+
![SSM-Menu](../../../assets/aws-ssm/search.png)
60+
61+
Go to Parameter Store
62+
63+
![Parameter-Store](../../../assets/aws-ssm/ssm-menu.png)
64+
65+
Create a new SSM Param called 'my-feature-flag' in your AWS Account and then retrieve it via OpenFeature Client!
66+
67+
![Create-Param](../../../assets/aws-ssm/create-param.png)
3668

3769
```
3870
const featureFlags = OpenFeature.getClient();

libs/providers/aws-ssm/src/lib/aws-ssm-provider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class AwsSsmProvider implements Provider {
2222
cache: Cache;
2323

2424
constructor(config: AwsSsmProviderConfig) {
25-
this.service = new SSMService(config.ssmClientConfig);
25+
this.service = new SSMService(config.ssmClientConfig, config.enableDecryption);
2626
this.cache = new Cache(config.cacheOpts);
2727
}
2828

libs/providers/aws-ssm/src/lib/cache.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ export class Cache {
88
private enabled: boolean;
99
constructor(opts: LRUCacheConfig) {
1010
this.cache = new LRUCache({
11-
maxSize: opts.size,
11+
maxSize: opts.size ?? 1000,
1212
sizeCalculation: () => 1,
1313
});
14-
this.ttl = opts.ttl;
14+
this.ttl = opts.ttl ?? 300000;
1515
this.enabled = opts.enabled;
1616
}
1717

libs/providers/aws-ssm/src/lib/ssm-service.ts

+36-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { GetParameterCommand, SSMClient, SSMClientConfig } from '@aws-sdk/client-ssm';
1+
import {
2+
GetParameterCommand,
3+
SSMClient,
4+
SSMClientConfig,
5+
GetParameterCommandInput,
6+
DescribeParametersCommand,
7+
} from '@aws-sdk/client-ssm';
28
import { ResponseMetadata } from '@smithy/types';
39
import {
410
FlagNotFoundError,
@@ -11,9 +17,10 @@ import {
1117

1218
export class SSMService {
1319
client: SSMClient;
14-
15-
constructor(config: SSMClientConfig) {
20+
enableDecryption: boolean;
21+
constructor(config: SSMClientConfig, enableDecryption?: boolean) {
1622
this.client = new SSMClient(config);
23+
this.enableDecryption = enableDecryption ?? false;
1724
}
1825

1926
async getBooleanValue(name: string): Promise<ResolutionDetails<boolean>> {
@@ -78,10 +85,34 @@ export class SSMService {
7885
}
7986
}
8087

88+
async _isSecureString(name: string): Promise<boolean> {
89+
const res = await this.client.send(
90+
new DescribeParametersCommand({
91+
ParameterFilters: [
92+
{
93+
Key: 'Name',
94+
Values: [name],
95+
},
96+
],
97+
}),
98+
);
99+
100+
if (!res.Parameters) {
101+
throw new FlagNotFoundError(`Unable to find an SSM Parameter with key ${name}`);
102+
}
103+
return res.Parameters[0].Type === 'SecureString';
104+
}
105+
81106
async _getValueFromSSM(name: string): Promise<{ val: string; metadata: ResponseMetadata }> {
82-
const command: GetParameterCommand = new GetParameterCommand({
107+
const param: GetParameterCommandInput = {
83108
Name: name,
84-
});
109+
};
110+
111+
if (this.enableDecryption) {
112+
param.WithDecryption = await this._isSecureString(name);
113+
}
114+
115+
const command: GetParameterCommand = new GetParameterCommand(param);
85116

86117
const res = await this.client.send(command);
87118

libs/providers/aws-ssm/src/lib/types.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { SSMClientConfig } from '@aws-sdk/client-ssm';
33
export type AwsSsmProviderConfig = {
44
ssmClientConfig: SSMClientConfig;
55
cacheOpts: LRUCacheConfig;
6+
enableDecryption?: boolean;
67
};
78

89
export type LRUCacheConfig = {
910
enabled: boolean;
10-
ttl: number;
11-
size: number;
11+
ttl?: number;
12+
size?: number;
1213
};

0 commit comments

Comments
 (0)