(aws-ssm): stringListValue returns unsplit list as string instead of list of strings
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### What is the problem?
When using a `StringListParameter` imported from an existing string list parameter with `StringListParameter.fromStringListParameterName`, the resulting value from `ipListParam.stringListValue` ends up being a single string with the unsplit list in it, instead of the expected list of strings.
My use-case is using the `StringListParameter` to store a list of IP addresses to be used in a `ResourcePolicy`, like so:
```typescript
const ipListParam = new StringListParameter(this, "ip-list", {
stringListValue: ["x.x.x.1", "x.x.x.2"],
parameterName: "ipList",
});
const apiResourcePolicy = new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
principals: [new AnyPrincipal()],
resources: ["execute-api:/*/*/*"],
actions: ["execute-api:Invoke"],
conditions: {
IpAddress: {
"aws:SourceIp": ipListParam.stringListValue,
},
},
}),
],
});
```
### Reproduction Steps
I created a new Typescript CDK project using `aws-cdk-lib=2.15.0`, and deployed the following stack to create the parameter, REST API Gateway, and resource policy:
Sample 1 (working):
```typescript
import { aws_apigateway, RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { EndpointType } from "aws-cdk-lib/aws-apigateway";
import {
AnyPrincipal,
Effect,
PolicyDocument,
PolicyStatement,
} from "aws-cdk-lib/aws-iam";
import { StringListParameter } from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";
export class StringlistTestStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const ipListParam = new StringListParameter(this, "ip-list", {
stringListValue: ["x.x.x.1", "x.x.x.2"],
parameterName: "ipList",
});
ipListParam.applyRemovalPolicy(RemovalPolicy.RETAIN);
const apiResourcePolicy = new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
principals: [new AnyPrincipal()],
resources: ["execute-api:/*/*/*"],
actions: ["execute-api:Invoke"],
conditions: {
IpAddress: {
"aws:SourceIp": ipListParam.stringListValue,
},
},
}),
],
});
const api = new aws_apigateway.RestApi(this, "pudim-api", {
policy: apiResourcePolicy,
endpointTypes: [EndpointType.REGIONAL],
});
const item = api.root.addResource("item");
item.addMethod(
"GET",
new aws_apigateway.HttpIntegration("http://www.pudim.com.br")
);
}
}
```
Then, I removed `ipList` from the stack while retaining the parameter, and imported it by its name again.
Sample 2 (not working):
```typescript
import { aws_apigateway, RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { EndpointType } from "aws-cdk-lib/aws-apigateway";
import {
AnyPrincipal,
Effect,
PolicyDocument,
PolicyStatement,
} from "aws-cdk-lib/aws-iam";
import { StringListParameter } from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";
export class StringlistTestStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const ipListParam = StringListParameter.fromStringListParameterName(
this,
"ip-list",
"ipList"
);
const apiResourcePolicy = new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
principals: [new AnyPrincipal()],
resources: ["execute-api:/*/*/*"],
actions: ["execute-api:Invoke"],
conditions: {
IpAddress: {
"aws:SourceIp": ipListParam.stringListValue,
},
},
}),
],
});
const api = new aws_apigateway.RestApi(this, "pudim-api", {
policy: apiResourcePolicy,
endpointTypes: [EndpointType.REGIONAL],
});
const item = api.root.addResource("item");
item.addMethod(
"GET",
new aws_apigateway.HttpIntegration("http://www.pudim.com.br")
);
}
}
```
### What did you expect to happen?
The API should be accessible for the IP addresses in the `StringListParameter` `ipList`.
I deployed and tested the endpoint resulting from Sample 1, and it worked as expected. The generated resource policy associated with the REST API Gateway was also correct (note the list in `aws:SourceIp`:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:eu-central-1::/*/*/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"x.x.x.1",
"x.x.x.2"
]
}
}
}
]
}
```
### What actually happened?
The API was not accessible, and the generated resource policy now contained a comma-separated string of IP addresses.
Generated resource policy:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:eu-central-1::/*/*/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "x.x.x.1,x.x.x.2"
}
}
}
]
}
```
I had the same problem with CDK `1.147.0`.
### CDK CLI Version
2.15.0 (build 151055e)
### Framework Version
?
### Node.js Version
v16.14.0
### OS
macOS 12.2.1 (21D62)
### Language
Typescript
### Language Version
Typescript 3.9.7
### Other information
When deploying, this is the change to the policy as presented by CDK:
```
IAM Statement Changes
┌───┬────────────────────┬────────┬────────────────────┬───────────┬──────────────────────────────────────────────────────────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼────────────────────┼────────┼────────────────────┼───────────┼──────────────────────────────────────────────────────────────┤
│ - │ execute-api:/*/*/* │ Allow │ execute-api:Invoke │ AWS:* │ "IpAddress": { │
│ │ │ │ │ │ "aws:SourceIp": "{\"Fn::Split\":[\",\",\"${iplist29786949. │
│ │ │ │ │ │ Value}\"]}" │
│ │ │ │ │ │ } │
├───┼────────────────────┼────────┼────────────────────┼───────────┼──────────────────────────────────────────────────────────────┤
│ + │ execute-api:/*/*/* │ Allow │ execute-api:Invoke │ AWS:* │ "IpAddress": { │
│ │ │ │ │ │ "aws:SourceIp": "{\"Fn::Split\":[\",\",\"{{resolve:ssm:ipL │
│ │ │ │ │ │ ist}}\"]}" │
│ │ │ │ │ │ } │
└───┴────────────────────┴────────┴────────────────────┴───────────┴──────────────────────────────────────────────────────────────┘
```
Contributor guide
Assessment
This issue has not been assessed yet.